* [PATCH] pinctrl: mediatek: add eint new design for mt8196
@ 2024-10-25 3:16 chang hao
2024-10-25 4:12 ` Chen-Yu Tsai
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: chang hao @ 2024-10-25 3:16 UTC (permalink / raw)
To: matthias.bgg, angelogioacchino.delregno, sean.wang, linus.walleij
Cc: linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel,
Chhao Chang
From: Chhao Chang <ot_chhao.chang@mediatek.com>
eint is divided from the original base address into base addresses
in five directions: east, south, west, north, and center.
Stores a limited number of eint numbers in each direction.
Signed-off-by: Chhao Chang <ot_chhao.chang@mediatek.com>
---
drivers/pinctrl/mediatek/mtk-eint.c | 831 +++++++++++++-----
drivers/pinctrl/mediatek/mtk-eint.h | 75 +-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 50 +-
3 files changed, 723 insertions(+), 233 deletions(-)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 27f0a54e12bf..57f812299340 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -17,16 +17,13 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of_irq.h>
+#include <linux/of_address.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_MAX 16
-#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
-#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
+static struct mtk_eint *global_eintc;
+struct mtk_eint_pin pin;
static const struct mtk_eint_regs mtk_generic_eint_regs = {
.stat = 0x000,
@@ -47,6 +44,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
+ .event = 0x800,
+ .event_set = 0x840,
+ .event_clr = 0x880,
+ .raw_stat = 0xa00,
};
const unsigned int debounce_time_mt2701[] = {
@@ -64,60 +65,145 @@ const unsigned int debounce_time_mt6795[] = {
};
EXPORT_SYMBOL_GPL(debounce_time_mt6795);
-static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
+/*
+ * Return the iomem of specific register ofset and decode the coordinate
+ * (instance, index) from global eint number.
+ * If return NULL, then it must be either out-of-range or do-not-support.
+ */
+static void __iomem *mtk_eint_get_ofset(struct mtk_eint *eint,
unsigned int eint_num,
- unsigned int offset)
+ unsigned int ofset,
+ unsigned int *instance,
+ unsigned int *index)
{
- unsigned int eint_base = 0;
void __iomem *reg;
- if (eint_num >= eint->hw->ap_num)
- eint_base = eint->hw->ap_num;
+ if (eint_num >= eint->total_pin_number ||
+ !eint->pins[eint_num].enabled) {
+ WARN_ON(1);
+ return NULL;
+ }
- reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+ *instance = eint->pins[eint_num].instance;
+ *index = eint->pins[eint_num].index;
+ reg = eint->instances[*instance].base + ofset + (*index / MAX_BIT * REG_OFSET);
return reg;
}
+/*
+ * Generate helper function to access property register of a dedicate pin.
+ */
+#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFSET) \
+static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
+ unsigned int eint_num) \
+{ \
+ unsigned int instance, index; \
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num, \
+ _OFSET, \
+ &instance, &index); \
+ unsigned int bit = BIT(index & 0x1f);\
+\
+ if (!reg) { \
+ dev_err(eint->dev, "%s invalid eint_num %d\n", \
+ __func__, eint_num); \
+ return 0;\
+ } \
+\
+ return !!(readl(reg) & bit); \
+}
+
+DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
+DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
+DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
+DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
+DEFINE_EINT_GET_FUNCTION(dom_en, eint->comp->regs->dom_en);
+DEFINE_EINT_GET_FUNCTION(event, eint->comp->regs->event);
+DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
+
+int dump_eint_pin_status(unsigned int eint_num)
+{
+ unsigned int stat, raw_stat, mask, sens, pol, dom_en, event;
+
+ if (eint_num < 0 || eint_num > global_eintc->total_pin_number)
+ return ENODEV;
+
+ stat = mtk_eint_get_stat(global_eintc, eint_num);
+ raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
+ mask = mtk_eint_get_mask(global_eintc, eint_num);
+ sens = mtk_eint_get_sens(global_eintc, eint_num);
+ pol = mtk_eint_get_pol(global_eintc, eint_num);
+ dom_en = mtk_eint_get_dom_en(global_eintc, eint_num);
+ event = mtk_eint_get_event(global_eintc, eint_num);
+ dev_info(global_eintc->dev, "%s eint_num:%u=stat:%u,raw:%u, \
+ mask:%u, sens:%u,pol:%u,dom_en:%u,event:%u\n",
+ __func__, eint_num, stat, raw_stat, mask, sens,
+ pol, dom_en, event);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dump_eint_pin_status);
+
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->sens,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
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)
+ if (eint->pins[eint_num].debounce &&
+ sens != MTK_EINT_EDGE_SENSITIVE)
return 1;
else
return 0;
}
-static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)
{
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);
+ unsigned int reg_ofset;
+ unsigned int instance, index, mask, port;
+ void __iomem *reg;
- curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ mask = BIT(index & 0x1f);
+ port = index >> REG_GROUP;
+ reg = eint->instances[instance].base + port * REG_OFSET;
+
+ curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, eint_num);
do {
start_level = curr_level;
if (start_level)
- reg_offset = eint->regs->pol_clr;
+ reg_ofset = eint->comp->regs->pol_clr;
else
- reg_offset = eint->regs->pol_set;
- writel(mask, reg + reg_offset);
+ reg_ofset = eint->comp->regs->pol_set;
+
+ writel(mask, reg + reg_ofset);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
- hwirq);
+ eint_num);
} while (start_level != curr_level);
return start_level;
@@ -126,11 +212,19 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_set,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] &= ~mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] &= ~mask;
writel(mask, reg);
}
@@ -138,43 +232,91 @@ static void mtk_eint_mask(struct irq_data *d)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_clr,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] |= mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] |= mask;
writel(mask, reg);
- if (eint->dual_edge[d->hwirq])
+ if (eint->pins[d->hwirq].dual_edge)
mtk_eint_flip_edge(eint, d->hwirq);
}
-static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
+static void mtk_eint_ack(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ unsigned int instance, index;
+ void __iomem *reg;
+ unsigned int bit;
+
+ if (eint->comp->ops.ack)
+ eint->comp->ops.ack(d);
+ else {
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->ack,
+ &instance, &index);
+ bit = BIT(index & 0x1f);
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
+
+ writel(bit, reg);
+ }
+}
+
+static void mtk_eint_soft_set(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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_set,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- return !!(readl(reg) & bit);
+ writel(bit, reg);
}
-static void mtk_eint_ack(struct irq_data *d)
+static void mtk_eint_soft_clr(struct mtk_eint *eint,
+ unsigned int eint_num)
{
- 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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_clr,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- writel(mask, reg);
+ writel(bit, 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);
- bool masked;
- u32 mask = BIT(d->hwirq & 0x1f);
+ u32 mask;
+ unsigned int instance, index;
void __iomem *reg;
if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
@@ -186,36 +328,42 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
}
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- eint->dual_edge[d->hwirq] = 1;
+ eint->pins[d->hwirq].dual_edge = 1;
else
- eint->dual_edge[d->hwirq] = 0;
+ eint->pins[d->hwirq].dual_edge = 0;
- if (!mtk_eint_get_mask(eint, d->hwirq)) {
- mtk_eint_mask(d);
- masked = false;
- } else {
- masked = true;
- }
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_set,
+ &instance, &index);
- 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);
- }
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_set,
+ &instance, &index);
- 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 (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
}
- mtk_eint_ack(d);
- if (!masked)
- mtk_eint_unmask(d);
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (eint->pins[d->hwirq].dual_edge)
+ mtk_eint_flip_edge(eint, d->hwirq);
return 0;
}
@@ -223,30 +371,28 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
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;
+ unsigned int instance, index, shift, port;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
+ }
+
+ shift = index & 0x1f;
+ port = index >> REG_GROUP;
if (on)
- eint->wake_mask[reg] |= BIT(shift);
+ eint->instances[instance].wake_mask[port] |= BIT(shift);
else
- eint->wake_mask[reg] &= ~BIT(shift);
+ eint->instances[instance].wake_mask[port] &= ~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 int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -290,7 +436,7 @@ static void mtk_eint_irq_release_resources(struct irq_data *d)
}
static struct irq_chip mtk_eint_irq_chip = {
- .name = "mt-eint",
+ .name = "mtk-eint",
.irq_disable = mtk_eint_mask,
.irq_mask = mtk_eint_mask,
.irq_unmask = mtk_eint_unmask,
@@ -301,35 +447,51 @@ static struct irq_chip mtk_eint_irq_chip = {
.irq_release_resources = mtk_eint_irq_release_resources,
};
+/*
+ * Configure all EINT pins as domain 0, which only belongs to AP.
+ */
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
- void __iomem *dom_en = eint->base + eint->regs->dom_en;
- void __iomem *mask_set = eint->base + eint->regs->mask_set;
- unsigned int i;
-
- for (i = 0; i < eint->hw->ap_num; i += 32) {
- writel(0xffffffff, dom_en);
- writel(0xffffffff, mask_set);
- dom_en += 4;
- mask_set += 4;
+ void __iomem *reg,*eevt_clr;
+ unsigned int i, j;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ reg = eint->instances[i].base + eint->comp->regs->dom_en;
+ eevt_clr = eint->instances[i].base + eint->comp->regs->event_clr;
+ for (j = 0; j < eint->instances[i].number; j += MAX_BIT, reg += REG_OFSET, eevt_clr += REG_OFSET) {
+ writel(REG_VAL, reg);
+ writel(REG_VAL, eevt_clr);
+ }
}
return 0;
}
static inline void
-mtk_eint_debounce_process(struct mtk_eint *eint, int index)
+mtk_eint_debounce_process(struct mtk_eint *eint, int eint_num)
{
- unsigned int rst, ctrl_offset;
+ unsigned int rst, ctrl_ofset;
unsigned int bit, dbnc;
+ unsigned int instance, index;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
+
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+ dbnc = readl(eint->instances[instance].base + ctrl_ofset);
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
- 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);
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ rst = MTK_EINT_DBNC_RST_BIT << ((index % REG_OFSET) * DB_GROUP);
+ writel(rst, eint->instances[instance].base + ctrl_ofset);
}
}
@@ -337,65 +499,72 @@ 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, mask_offset, index;
- void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
- int dual_edge, start_level, curr_level;
+ unsigned int status, i, j;
+ int shift, port, eint_num, virq;
+ unsigned int dual_edge, start_level, curr_level;
+ struct mtk_eint_instance eint_instance;
+ void __iomem *addr;
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);
- mask_offset = eint_num >> 5;
- index = eint_num + offset;
- status &= ~BIT(offset);
-
- /*
- * If we get an interrupt on pin that was only required
- * for wake (but no real interrupt requested), mask the
- * interrupt (as would mtk_eint_resume do anyway later
- * in the resume sequence).
- */
- if (eint->wake_mask[mask_offset] & BIT(offset) &&
- !(eint->cur_mask[mask_offset] & BIT(offset))) {
- writel_relaxed(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->mask_set);
- }
-
- 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);
- }
+ for (i = 0; i < eint->instance_number; i++) {
+ eint_instance = eint->instances[i];
- generic_handle_domain_irq(eint->domain, index);
+ /* Iterate all pins by port */
+ for (j = 0; j < eint_instance.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ status = readl(eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->stat);
+ while (status) {
+ shift = __ffs(status);
+ status &= ~BIT(shift);
- if (dual_edge) {
- curr_level = mtk_eint_flip_edge(eint, index);
+ eint_num = eint->instances[i].pin_list[shift + j];
+ virq = irq_find_mapping(eint->domain, eint_num);
/*
- * If level changed, we might lost one edge
- * interrupt, raised it through soft-irq.
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
*/
- if (start_level != curr_level)
- writel(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->soft_set);
- }
+ if (eint->instances[i].wake_mask[port] & BIT(shift) &&
+ !(eint->instances[i].cur_mask[port] & BIT(shift))) {
+ addr = eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->mask_set;
+ writel_relaxed(BIT(shift), addr);
+ }
+
+ dual_edge = eint->pins[eint_num].dual_edge;
+ if (dual_edge) {
+ /*
+ * Clear soft-irq in case we raised it last
+ * time.
+ */
+ mtk_eint_soft_clr(eint, eint_num);
+
+ start_level =
+ eint->gpio_xlate->get_gpio_state(eint->pctl,
+ eint_num);
+ }
+
+ generic_handle_irq(virq);
+
+ if (dual_edge) {
+ curr_level = mtk_eint_flip_edge(eint, eint_num);
+
+ /*
+ * If level changed, we might lost one edge
+ * interrupt, raised it through soft-irq.
+ */
+ if (start_level != curr_level)
+ mtk_eint_soft_set(eint, eint_num);
+ }
+
+ if (eint->pins[eint_num].debounce)
+ mtk_eint_debounce_process(eint, eint_num);
- if (index < eint->hw->db_cnt)
- mtk_eint_debounce_process(eint, index);
+ }
}
}
chained_irq_exit(chip, desc);
@@ -403,7 +572,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -411,7 +593,20 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
int mtk_eint_do_resume(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -420,27 +615,45 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
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,
+ int virq, eint_ofset;
+ unsigned int set_ofset, bit, clr_bit, clr_ofset, rst, i, unmask,
dbnc;
+ static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
+ 20000, 40000, 80000, 160000, 320000, 640000 };
struct irq_data *d;
+ unsigned int instance, index;
+ void __iomem *reg;
- if (!eint->hw->db_time)
- return -EOPNOTSUPP;
+ /*
+ * Due to different number of bit field, we only decode
+ * the coordinate here, instead of get the VA.
+ */
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, eint_num);
+ return 0;
+ }
virq = irq_find_mapping(eint->domain, eint_num);
- eint_offset = (eint_num % 4) * 8;
+ eint_ofset = (index % REG_OFSET) * DB_GROUP;
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;
+ reg = eint->instances[instance].base;
+ set_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ clr_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
- dbnc = eint->num_db_time;
- for (i = 0; i < eint->num_db_time; i++) {
- if (debounce <= eint->hw->db_time[i]) {
+ /*
+ * Check eint number to avoid access out-of-range
+ */
+ dbnc = ARRAY_SIZE(debounce_time) - 1;
+ for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+ if (debounce <= debounce_time[i]) {
dbnc = i;
break;
}
@@ -449,23 +662,20 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
if (!mtk_eint_get_mask(eint, eint_num)) {
mtk_eint_mask(d);
unmask = 1;
- } else {
+ } else
unmask = 0;
- }
- clr_bit = 0xff << eint_offset;
- writel(clr_bit, eint->base + clr_offset);
+ clr_bit = 0xff << eint_ofset;
+ writel(clr_bit, reg + clr_ofset);
- 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);
+ bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS)
+ | MTK_EINT_DBNC_SET_EN) << eint_ofset;
+ rst = MTK_EINT_DBNC_RST_BIT << eint_ofset;
+ writel(rst | bit, reg + set_ofset);
/*
- * Delay a while (more than 2T) to wait for hw debounce counter reset
- * work correctly.
+ * Delay should be (8T @ 32k) from dbc rst to work correctly.
*/
- udelay(1);
if (unmask == 1)
mtk_eint_unmask(d);
@@ -473,6 +683,53 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
}
EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
+unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, bit;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
+
+ return (readl(reg) & bit) ? 1 : 0;
+}
+
+unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, mask, ofset;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ ofset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % REG_OFSET) * DB_GROUP);
+ mask = 0xf << ofset;
+
+ return ((readl(reg) & mask) >> ofset);
+}
+
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
int irq;
@@ -485,45 +742,209 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
}
EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
+static const struct mtk_eint_compatible default_compat = {
+ .regs = &mtk_generic_eint_regs,
+};
+
+static const struct of_device_id eint_compatible_ids[] = {
+ { }
+};
+
int mtk_eint_do_init(struct mtk_eint *eint)
{
- int i;
+ int i, virq;
+ unsigned int size, inst = 0;
+ eint->instance_number = 1;
+ eint->total_pin_number = eint->hw->ap_num;
+
+ for (i = 0; i < eint->total_pin_number; i++) {
+ eint->pins[i].enabled = true;
+ eint->pins[i].instance = inst;
+ eint->pins[i].index = i;
+ eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
+
+ eint->instances[inst].pin_list[i] = i;
+ eint->instances[inst].number++;
+ }
- /* If clients don't assign a specific regs, let's use generic one */
- if (!eint->regs)
- eint->regs = &mtk_generic_eint_regs;
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
- eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->wake_mask), GFP_KERNEL);
- if (!eint->wake_mask)
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
+ eint->domain = irq_domain_add_linear(eint->dev->of_node,
+ eint->total_pin_number,
+ &irq_domain_simple_ops, NULL);
+ if (!eint->domain)
return -ENOMEM;
- eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->cur_mask), GFP_KERNEL);
- if (!eint->cur_mask)
+ mtk_eint_hw_init(eint);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ 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);
+
+ global_eintc = eint;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+
+int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ int i, virq, matrix_number = 0;
+ struct device_node *node;
+ unsigned int ret, size, ofset;
+ unsigned int id, inst, idx, support_deb;
+
+ const phandle *ph;
+
+ ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
+ if (!ph) {
+ dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
+ return -ENODEV;
+ }
+
+ node = of_find_node_by_phandle(be32_to_cpup(ph));
+ if (!node) {
+ dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(node, "mediatek,total-pin-number",
+ &eint->total_pin_number);
+ if (ret) {
+ dev_err(eint->dev,
+ "%s cannot read total-pin-number from device node.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
+ eint->total_pin_number);
+
+ ret = of_property_read_u32(node, "mediatek,instance-num",
+ &eint->instance_number);
+ if (ret)
+ eint->instance_number = 1; // only 1 instance in legacy chip
+
+ size = eint->instance_number * sizeof(struct mtk_eint_instance);
+ eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->instances)
return -ENOMEM;
- eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
- sizeof(int), GFP_KERNEL);
- if (!eint->dual_edge)
+ size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
+ eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->pins)
return -ENOMEM;
+ for (i = 0; i < eint->instance_number; i++) {
+ ret = of_property_read_string_index(node, "reg-name", i,
+ &(eint->instances[i].name));
+ if (ret) {
+ dev_info(eint->dev,
+ "%s cannot read the name of instance %d.\n",
+ __func__, i);
+ }
+
+ eint->instances[i].base = of_iomap(node, i);
+ if (!eint->instances[i].base)
+ return -ENOMEM;
+ }
+
+ matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
+ if (matrix_number < 0) {
+ matrix_number = eint->total_pin_number;
+ dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+ } else
+ dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+
+ for (i = 0; i < matrix_number; i++) {
+ ofset = i * REG_OFSET;
+
+ ret = of_property_read_u32_index(node, "mediatek,pins",
+ ofset, &id);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+FIRST, &inst);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+SECOND, &idx);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+THIRD, &support_deb);
+
+ /* Legacy chip which no need to give coordinate list */
+ if (ret) {
+ id = i;
+ inst = 0;
+ idx = i;
+ support_deb = (i < MAX_BIT) ? 1 : 0;
+ }
+
+ eint->pins[id].enabled = true;
+ eint->pins[id].instance = inst;
+ eint->pins[id].index = idx;
+ eint->pins[id].debounce = support_deb;
+
+ eint->instances[inst].pin_list[idx] = id;
+ eint->instances[inst].number++;
+
+#if defined(MTK_EINT_DEBUG)
+ pin = eint->pins[id];
+ dev_info(eint->dev,
+ "EINT%u in (%u-%u), su_deb = %u",
+ id,
+ pin.instance,
+ eint->instances[inst].number,
+ pin.debounce,
+#endif
+ }
+
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
+ eint->irq = irq_of_parse_and_map(node, 0);
+ if (!eint->irq) {
+ dev_err(eint->dev,
+ "%s IRQ parse fail.\n", __func__);
+ return -EINVAL;
+ }
+
eint->domain = irq_domain_add_linear(eint->dev->of_node,
- eint->hw->ap_num,
+ eint->total_pin_number,
&irq_domain_simple_ops, NULL);
if (!eint->domain)
return -ENOMEM;
- if (eint->hw->db_time) {
- for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
- if (eint->hw->db_time[i] == 0)
- break;
- eint->num_db_time = i;
- }
-
mtk_eint_hw_init(eint);
- for (i = 0; i < eint->hw->ap_num; i++) {
- int virq = irq_create_mapping(eint->domain, i);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ virq = irq_create_mapping(eint->domain, i);
irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
handle_level_irq);
@@ -533,9 +954,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)
irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
eint);
+ global_eintc = eint;
+
return 0;
}
-EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+EXPORT_SYMBOL_GPL(mtk_eint_do_init_v2);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MediaTek EINT Driver");
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 6139b16cd225..aa17a6073029 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -11,6 +11,25 @@
#include <linux/irqdomain.h>
+#define MAX_PIN 999
+#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)
+#define MTK_EINT_NO_OFSET 0
+#define MAX_BIT 32
+#define REG_OFSET 4
+#define REG_GROUP 5
+#define REG_VAL 0xFFFFFFFF
+#define DB_GROUP 8
+#define FIRST 1
+#define SECOND 2
+#define THIRD 3
+#define ARRAY_0 4
+
+//#define MTK_EINT_DEBUG
+
struct mtk_eint_regs {
unsigned int stat;
unsigned int ack;
@@ -30,6 +49,36 @@ struct mtk_eint_regs {
unsigned int dbnc_ctrl;
unsigned int dbnc_set;
unsigned int dbnc_clr;
+ unsigned int event;
+ unsigned int event_set;
+ unsigned int event_clr;
+ unsigned int raw_stat;
+};
+
+struct mtk_eint_ops {
+ void (*ack)(struct irq_data *d);
+};
+
+struct mtk_eint_compatible {
+ struct mtk_eint_ops ops;
+ const struct mtk_eint_regs *regs;
+};
+
+struct mtk_eint_instance {
+ const char *name;
+ void __iomem *base;
+ unsigned int number;
+ unsigned int pin_list[MAX_PIN];
+ unsigned int *wake_mask;
+ unsigned int *cur_mask;
+};
+
+struct mtk_eint_pin {
+ bool enabled;
+ unsigned int instance;
+ unsigned int index;
+ bool debounce;
+ bool dual_edge;
};
struct mtk_eint_hw {
@@ -60,11 +109,14 @@ struct mtk_eint {
struct irq_domain *domain;
int irq;
- int *dual_edge;
- u32 *wake_mask;
- u32 *cur_mask;
-
- /* Used to fit into various EINT device */
+ /* An array to record the coordinate, index by global EINT ID */
+ struct mtk_eint_pin *pins;
+ /* An array to record the global EINT ID, index by coordinate*/
+ struct mtk_eint_instance *instances;
+ unsigned int total_pin_number;
+ unsigned int instance_number;
+ unsigned int dump_target_eint;
+ const struct mtk_eint_compatible *comp;
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
u16 num_db_time;
@@ -74,13 +126,15 @@ struct mtk_eint {
const struct mtk_eint_xt *gpio_xlate;
};
-#if IS_ENABLED(CONFIG_EINT_MTK)
+#if (IS_ENABLED(CONFIG_EINT_MTK) || IS_ENABLED(CONFIG_DEVICE_MODULES_EINT_MTK))
int mtk_eint_do_init(struct mtk_eint *eint);
+int mtk_eint_do_init_v2(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);
+int dump_eint_pin_status(unsigned int eint_num);
#else
static inline int mtk_eint_do_init(struct mtk_eint *eint)
@@ -88,6 +142,11 @@ static inline int mtk_eint_do_init(struct mtk_eint *eint)
return -EOPNOTSUPP;
}
+static inline int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
@@ -108,5 +167,9 @@ static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
return -EOPNOTSUPP;
}
+static inline int dump_eint_pin_status(unsigned int eint_num)
+{
+ return -EOPNOTSUPP;
+}
#endif
#endif /* __MTK_EINT_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index 54301fbba524..3740e868c650 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -375,33 +375,37 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
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;
-
- hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
- if (IS_ERR(hw->eint->base)) {
- ret = PTR_ERR(hw->eint->base);
- goto err_free_eint;
- }
+ if (hw->soc->eint_hw) {
+ hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
+ if (!hw->eint)
+ return -ENOMEM;
+
+ hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
+ if (IS_ERR(hw->eint->base)) {
+ ret = PTR_ERR(hw->eint->base);
+ goto err_free_eint;
+ }
- hw->eint->irq = irq_of_parse_and_map(np, 0);
- if (!hw->eint->irq) {
- ret = -EINVAL;
- goto err_free_eint;
- }
+ hw->eint->irq = irq_of_parse_and_map(np, 0);
+ if (!hw->eint->irq) {
+ ret = -EINVAL;
+ goto err_free_eint;
+ }
- if (!hw->soc->eint_hw) {
- ret = -ENODEV;
- goto err_free_eint;
- }
+ 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);
- hw->eint->dev = &pdev->dev;
- hw->eint->hw = hw->soc->eint_hw;
- hw->eint->pctl = hw;
- hw->eint->gpio_xlate = &mtk_eint_xt;
+ } else {
+ hw->eint->dev = &pdev->dev;
+ hw->eint->pctl = hw;
+ hw->eint->gpio_xlate = &mtk_eint_xt;
- return mtk_eint_do_init(hw->eint);
+ return mtk_eint_do_init_v2(hw->eint);
+ }
err_free_eint:
devm_kfree(hw->dev, hw->eint);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
2024-10-25 3:16 [PATCH] pinctrl: mediatek: add eint new design for mt8196 chang hao
@ 2024-10-25 4:12 ` Chen-Yu Tsai
2024-10-26 18:27 ` kernel test robot
` (2 subsequent siblings)
3 siblings, 0 replies; 13+ messages in thread
From: Chen-Yu Tsai @ 2024-10-25 4:12 UTC (permalink / raw)
To: chang hao
Cc: matthias.bgg, angelogioacchino.delregno, sean.wang, linus.walleij,
linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel
On Fri, Oct 25, 2024 at 11:19 AM chang hao <ot_chhao.chang@mediatek.com> wrote:
>
> From: Chhao Chang <ot_chhao.chang@mediatek.com>
Please properly version your patch, and also add changelogs. You have
sent three already and I have no idea which one is which version or
what changed.
ChenYu
> eint is divided from the original base address into base addresses
> in five directions: east, south, west, north, and center.
> Stores a limited number of eint numbers in each direction.
>
> Signed-off-by: Chhao Chang <ot_chhao.chang@mediatek.com>
> ---
> drivers/pinctrl/mediatek/mtk-eint.c | 831 +++++++++++++-----
> drivers/pinctrl/mediatek/mtk-eint.h | 75 +-
> .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 50 +-
> 3 files changed, 723 insertions(+), 233 deletions(-)
>
> diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
> index 27f0a54e12bf..57f812299340 100644
> --- a/drivers/pinctrl/mediatek/mtk-eint.c
> +++ b/drivers/pinctrl/mediatek/mtk-eint.c
> @@ -17,16 +17,13 @@
> #include <linux/irqdomain.h>
> #include <linux/module.h>
> #include <linux/of_irq.h>
> +#include <linux/of_address.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_MAX 16
> -#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
> -#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
> +static struct mtk_eint *global_eintc;
> +struct mtk_eint_pin pin;
>
> static const struct mtk_eint_regs mtk_generic_eint_regs = {
> .stat = 0x000,
> @@ -47,6 +44,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
> .dbnc_ctrl = 0x500,
> .dbnc_set = 0x600,
> .dbnc_clr = 0x700,
> + .event = 0x800,
> + .event_set = 0x840,
> + .event_clr = 0x880,
> + .raw_stat = 0xa00,
> };
>
> const unsigned int debounce_time_mt2701[] = {
> @@ -64,60 +65,145 @@ const unsigned int debounce_time_mt6795[] = {
> };
> EXPORT_SYMBOL_GPL(debounce_time_mt6795);
>
> -static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
> +/*
> + * Return the iomem of specific register ofset and decode the coordinate
> + * (instance, index) from global eint number.
> + * If return NULL, then it must be either out-of-range or do-not-support.
> + */
> +static void __iomem *mtk_eint_get_ofset(struct mtk_eint *eint,
> unsigned int eint_num,
> - unsigned int offset)
> + unsigned int ofset,
> + unsigned int *instance,
> + unsigned int *index)
> {
> - unsigned int eint_base = 0;
> void __iomem *reg;
>
> - if (eint_num >= eint->hw->ap_num)
> - eint_base = eint->hw->ap_num;
> + if (eint_num >= eint->total_pin_number ||
> + !eint->pins[eint_num].enabled) {
> + WARN_ON(1);
> + return NULL;
> + }
>
> - reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
> + *instance = eint->pins[eint_num].instance;
> + *index = eint->pins[eint_num].index;
> + reg = eint->instances[*instance].base + ofset + (*index / MAX_BIT * REG_OFSET);
>
> return reg;
> }
>
> +/*
> + * Generate helper function to access property register of a dedicate pin.
> + */
> +#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFSET) \
> +static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
> + unsigned int eint_num) \
> +{ \
> + unsigned int instance, index; \
> + void __iomem *reg = mtk_eint_get_ofset(eint, eint_num, \
> + _OFSET, \
> + &instance, &index); \
> + unsigned int bit = BIT(index & 0x1f);\
> +\
> + if (!reg) { \
> + dev_err(eint->dev, "%s invalid eint_num %d\n", \
> + __func__, eint_num); \
> + return 0;\
> + } \
> +\
> + return !!(readl(reg) & bit); \
> +}
> +
> +DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
> +DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
> +DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
> +DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
> +DEFINE_EINT_GET_FUNCTION(dom_en, eint->comp->regs->dom_en);
> +DEFINE_EINT_GET_FUNCTION(event, eint->comp->regs->event);
> +DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
> +
> +int dump_eint_pin_status(unsigned int eint_num)
> +{
> + unsigned int stat, raw_stat, mask, sens, pol, dom_en, event;
> +
> + if (eint_num < 0 || eint_num > global_eintc->total_pin_number)
> + return ENODEV;
> +
> + stat = mtk_eint_get_stat(global_eintc, eint_num);
> + raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
> + mask = mtk_eint_get_mask(global_eintc, eint_num);
> + sens = mtk_eint_get_sens(global_eintc, eint_num);
> + pol = mtk_eint_get_pol(global_eintc, eint_num);
> + dom_en = mtk_eint_get_dom_en(global_eintc, eint_num);
> + event = mtk_eint_get_event(global_eintc, eint_num);
> + dev_info(global_eintc->dev, "%s eint_num:%u=stat:%u,raw:%u, \
> + mask:%u, sens:%u,pol:%u,dom_en:%u,event:%u\n",
> + __func__, eint_num, stat, raw_stat, mask, sens,
> + pol, dom_en, event);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(dump_eint_pin_status);
> +
> 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);
> + unsigned int instance, index;
> + void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
> + eint->comp->regs->sens,
> + &instance, &index);
> + unsigned int bit = BIT(index & 0x1f);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return 0;
> + }
>
> 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)
> + if (eint->pins[eint_num].debounce &&
> + sens != MTK_EINT_EDGE_SENSITIVE)
> return 1;
> else
> return 0;
> }
>
> -static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
> +static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)
> {
> 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);
> + unsigned int reg_ofset;
> + unsigned int instance, index, mask, port;
> + void __iomem *reg;
>
> - curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
> + reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return 0;
> + }
> +
> + mask = BIT(index & 0x1f);
> + port = index >> REG_GROUP;
> + reg = eint->instances[instance].base + port * REG_OFSET;
> +
> + curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, eint_num);
>
> do {
> start_level = curr_level;
> if (start_level)
> - reg_offset = eint->regs->pol_clr;
> + reg_ofset = eint->comp->regs->pol_clr;
> else
> - reg_offset = eint->regs->pol_set;
> - writel(mask, reg + reg_offset);
> + reg_ofset = eint->comp->regs->pol_set;
> +
> + writel(mask, reg + reg_ofset);
>
> curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
> - hwirq);
> + eint_num);
> } while (start_level != curr_level);
>
> return start_level;
> @@ -126,11 +212,19 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
> 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);
> + unsigned int instance, index;
> + void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
> + eint->comp->regs->mask_set,
> + &instance, &index);
> + u32 mask = BIT(index & 0x1f);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %lu\n",
> + __func__, d->hwirq);
> + return;
> + }
>
> - eint->cur_mask[d->hwirq >> 5] &= ~mask;
> + eint->instances[instance].cur_mask[index >> REG_GROUP] &= ~mask;
>
> writel(mask, reg);
> }
> @@ -138,43 +232,91 @@ static void mtk_eint_mask(struct irq_data *d)
> 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);
> + unsigned int instance, index;
> + void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
> + eint->comp->regs->mask_clr,
> + &instance, &index);
> + u32 mask = BIT(index & 0x1f);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %lu\n",
> + __func__, d->hwirq);
> + return;
> + }
>
> - eint->cur_mask[d->hwirq >> 5] |= mask;
> + eint->instances[instance].cur_mask[index >> REG_GROUP] |= mask;
>
> writel(mask, reg);
>
> - if (eint->dual_edge[d->hwirq])
> + if (eint->pins[d->hwirq].dual_edge)
> mtk_eint_flip_edge(eint, d->hwirq);
> }
>
> -static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
> +static void mtk_eint_ack(struct irq_data *d)
> +{
> + struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
> + unsigned int instance, index;
> + void __iomem *reg;
> + unsigned int bit;
> +
> + if (eint->comp->ops.ack)
> + eint->comp->ops.ack(d);
> + else {
> + reg = mtk_eint_get_ofset(eint, d->hwirq,
> + eint->comp->regs->ack,
> + &instance, &index);
> + bit = BIT(index & 0x1f);
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %lu\n",
> + __func__, d->hwirq);
> + return;
> + }
> +
> + writel(bit, reg);
> + }
> +}
> +
> +static void mtk_eint_soft_set(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);
> + unsigned int instance, index;
> + void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
> + eint->comp->regs->soft_set,
> + &instance, &index);
> + unsigned int bit = BIT(index & 0x1f);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return;
> + }
>
> - return !!(readl(reg) & bit);
> + writel(bit, reg);
> }
>
> -static void mtk_eint_ack(struct irq_data *d)
> +static void mtk_eint_soft_clr(struct mtk_eint *eint,
> + unsigned int eint_num)
> {
> - 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);
> + unsigned int instance, index;
> + void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
> + eint->comp->regs->soft_clr,
> + &instance, &index);
> + unsigned int bit = BIT(index & 0x1f);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return;
> + }
>
> - writel(mask, reg);
> + writel(bit, 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);
> - bool masked;
> - u32 mask = BIT(d->hwirq & 0x1f);
> + u32 mask;
> + unsigned int instance, index;
> void __iomem *reg;
>
> if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
> @@ -186,36 +328,42 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
> }
>
> if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
> - eint->dual_edge[d->hwirq] = 1;
> + eint->pins[d->hwirq].dual_edge = 1;
> else
> - eint->dual_edge[d->hwirq] = 0;
> + eint->pins[d->hwirq].dual_edge = 0;
>
> - if (!mtk_eint_get_mask(eint, d->hwirq)) {
> - mtk_eint_mask(d);
> - masked = false;
> - } else {
> - masked = true;
> - }
> + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
> + reg = mtk_eint_get_ofset(eint, d->hwirq,
> + eint->comp->regs->pol_clr,
> + &instance, &index);
> + else
> + reg = mtk_eint_get_ofset(eint, d->hwirq,
> + eint->comp->regs->pol_set,
> + &instance, &index);
>
> - 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);
> - }
> + mask = BIT(index & 0x1f);
> + writel(mask, reg);
> +
> + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
> + reg = mtk_eint_get_ofset(eint, d->hwirq,
> + eint->comp->regs->sens_clr,
> + &instance, &index);
> + else
> + reg = mtk_eint_get_ofset(eint, d->hwirq,
> + eint->comp->regs->sens_set,
> + &instance, &index);
>
> - 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 (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %lu\n",
> + __func__, d->hwirq);
> + return 0;
> }
>
> - mtk_eint_ack(d);
> - if (!masked)
> - mtk_eint_unmask(d);
> + mask = BIT(index & 0x1f);
> + writel(mask, reg);
> +
> + if (eint->pins[d->hwirq].dual_edge)
> + mtk_eint_flip_edge(eint, d->hwirq);
>
> return 0;
> }
> @@ -223,30 +371,28 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
> 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;
> + unsigned int instance, index, shift, port;
> + void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
> + MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %lu\n",
> + __func__, d->hwirq);
> + return 0;
> + }
> +
> + shift = index & 0x1f;
> + port = index >> REG_GROUP;
>
> if (on)
> - eint->wake_mask[reg] |= BIT(shift);
> + eint->instances[instance].wake_mask[port] |= BIT(shift);
> else
> - eint->wake_mask[reg] &= ~BIT(shift);
> + eint->instances[instance].wake_mask[port] &= ~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 int mtk_eint_irq_request_resources(struct irq_data *d)
> {
> struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
> @@ -290,7 +436,7 @@ static void mtk_eint_irq_release_resources(struct irq_data *d)
> }
>
> static struct irq_chip mtk_eint_irq_chip = {
> - .name = "mt-eint",
> + .name = "mtk-eint",
> .irq_disable = mtk_eint_mask,
> .irq_mask = mtk_eint_mask,
> .irq_unmask = mtk_eint_unmask,
> @@ -301,35 +447,51 @@ static struct irq_chip mtk_eint_irq_chip = {
> .irq_release_resources = mtk_eint_irq_release_resources,
> };
>
> +/*
> + * Configure all EINT pins as domain 0, which only belongs to AP.
> + */
> static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
> {
> - void __iomem *dom_en = eint->base + eint->regs->dom_en;
> - void __iomem *mask_set = eint->base + eint->regs->mask_set;
> - unsigned int i;
> -
> - for (i = 0; i < eint->hw->ap_num; i += 32) {
> - writel(0xffffffff, dom_en);
> - writel(0xffffffff, mask_set);
> - dom_en += 4;
> - mask_set += 4;
> + void __iomem *reg,*eevt_clr;
> + unsigned int i, j;
> +
> + for (i = 0; i < eint->instance_number; i++) {
> + reg = eint->instances[i].base + eint->comp->regs->dom_en;
> + eevt_clr = eint->instances[i].base + eint->comp->regs->event_clr;
> + for (j = 0; j < eint->instances[i].number; j += MAX_BIT, reg += REG_OFSET, eevt_clr += REG_OFSET) {
> + writel(REG_VAL, reg);
> + writel(REG_VAL, eevt_clr);
> + }
> }
>
> return 0;
> }
>
> static inline void
> -mtk_eint_debounce_process(struct mtk_eint *eint, int index)
> +mtk_eint_debounce_process(struct mtk_eint *eint, int eint_num)
> {
> - unsigned int rst, ctrl_offset;
> + unsigned int rst, ctrl_ofset;
> unsigned int bit, dbnc;
> + unsigned int instance, index;
> + void __iomem *reg;
> +
> + reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return;
> + }
> +
> + ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
> + dbnc = readl(eint->instances[instance].base + ctrl_ofset);
> + bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
>
> - 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);
> + ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
> + rst = MTK_EINT_DBNC_RST_BIT << ((index % REG_OFSET) * DB_GROUP);
> + writel(rst, eint->instances[instance].base + ctrl_ofset);
> }
> }
>
> @@ -337,65 +499,72 @@ 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, mask_offset, index;
> - void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
> - int dual_edge, start_level, curr_level;
> + unsigned int status, i, j;
> + int shift, port, eint_num, virq;
> + unsigned int dual_edge, start_level, curr_level;
> + struct mtk_eint_instance eint_instance;
> + void __iomem *addr;
>
> 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);
> - mask_offset = eint_num >> 5;
> - index = eint_num + offset;
> - status &= ~BIT(offset);
> -
> - /*
> - * If we get an interrupt on pin that was only required
> - * for wake (but no real interrupt requested), mask the
> - * interrupt (as would mtk_eint_resume do anyway later
> - * in the resume sequence).
> - */
> - if (eint->wake_mask[mask_offset] & BIT(offset) &&
> - !(eint->cur_mask[mask_offset] & BIT(offset))) {
> - writel_relaxed(BIT(offset), reg -
> - eint->regs->stat +
> - eint->regs->mask_set);
> - }
> -
> - 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);
> - }
> + for (i = 0; i < eint->instance_number; i++) {
> + eint_instance = eint->instances[i];
>
> - generic_handle_domain_irq(eint->domain, index);
> + /* Iterate all pins by port */
> + for (j = 0; j < eint_instance.number; j += MAX_BIT) {
> + port = j >> REG_GROUP;
> + status = readl(eint_instance.base + port * REG_OFSET +
> + eint->comp->regs->stat);
> + while (status) {
> + shift = __ffs(status);
> + status &= ~BIT(shift);
>
> - if (dual_edge) {
> - curr_level = mtk_eint_flip_edge(eint, index);
> + eint_num = eint->instances[i].pin_list[shift + j];
> + virq = irq_find_mapping(eint->domain, eint_num);
>
> /*
> - * If level changed, we might lost one edge
> - * interrupt, raised it through soft-irq.
> + * If we get an interrupt on pin that was only required
> + * for wake (but no real interrupt requested), mask the
> + * interrupt (as would mtk_eint_resume do anyway later
> + * in the resume sequence).
> */
> - if (start_level != curr_level)
> - writel(BIT(offset), reg -
> - eint->regs->stat +
> - eint->regs->soft_set);
> - }
> + if (eint->instances[i].wake_mask[port] & BIT(shift) &&
> + !(eint->instances[i].cur_mask[port] & BIT(shift))) {
> + addr = eint_instance.base + port * REG_OFSET +
> + eint->comp->regs->mask_set;
> + writel_relaxed(BIT(shift), addr);
> + }
> +
> + dual_edge = eint->pins[eint_num].dual_edge;
> + if (dual_edge) {
> + /*
> + * Clear soft-irq in case we raised it last
> + * time.
> + */
> + mtk_eint_soft_clr(eint, eint_num);
> +
> + start_level =
> + eint->gpio_xlate->get_gpio_state(eint->pctl,
> + eint_num);
> + }
> +
> + generic_handle_irq(virq);
> +
> + if (dual_edge) {
> + curr_level = mtk_eint_flip_edge(eint, eint_num);
> +
> + /*
> + * If level changed, we might lost one edge
> + * interrupt, raised it through soft-irq.
> + */
> + if (start_level != curr_level)
> + mtk_eint_soft_set(eint, eint_num);
> + }
> +
> + if (eint->pins[eint_num].debounce)
> + mtk_eint_debounce_process(eint, eint_num);
>
> - if (index < eint->hw->db_cnt)
> - mtk_eint_debounce_process(eint, index);
> + }
> }
> }
> chained_irq_exit(chip, desc);
> @@ -403,7 +572,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
>
> int mtk_eint_do_suspend(struct mtk_eint *eint)
> {
> - mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
> + unsigned int i, j, port;
> +
> + for (i = 0; i < eint->instance_number; i++) {
> + struct mtk_eint_instance inst = eint->instances[i];
> +
> + for (j = 0; j < inst.number; j += MAX_BIT) {
> + port = j >> REG_GROUP;
> + writel_relaxed(~inst.wake_mask[port],
> + inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
> + writel_relaxed(inst.wake_mask[port],
> + inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
> + }
> + }
> + dsb(sy);
>
> return 0;
> }
> @@ -411,7 +593,20 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
>
> int mtk_eint_do_resume(struct mtk_eint *eint)
> {
> - mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
> + unsigned int i, j, port;
> +
> + for (i = 0; i < eint->instance_number; i++) {
> + struct mtk_eint_instance inst = eint->instances[i];
> +
> + for (j = 0; j < inst.number; j += MAX_BIT) {
> + port = j >> REG_GROUP;
> + writel_relaxed(~inst.cur_mask[port],
> + inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
> + writel_relaxed(inst.cur_mask[port],
> + inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
> + }
> + }
> + dsb(sy);
>
> return 0;
> }
> @@ -420,27 +615,45 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
> 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,
> + int virq, eint_ofset;
> + unsigned int set_ofset, bit, clr_bit, clr_ofset, rst, i, unmask,
> dbnc;
> + static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
> + 20000, 40000, 80000, 160000, 320000, 640000 };
> struct irq_data *d;
> + unsigned int instance, index;
> + void __iomem *reg;
>
> - if (!eint->hw->db_time)
> - return -EOPNOTSUPP;
> + /*
> + * Due to different number of bit field, we only decode
> + * the coordinate here, instead of get the VA.
> + */
> + reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %lu\n",
> + __func__, eint_num);
> + return 0;
> + }
>
> virq = irq_find_mapping(eint->domain, eint_num);
> - eint_offset = (eint_num % 4) * 8;
> + eint_ofset = (index % REG_OFSET) * DB_GROUP;
> 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;
> + reg = eint->instances[instance].base;
> + set_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
> + clr_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_clr;
>
> if (!mtk_eint_can_en_debounce(eint, eint_num))
> return -EINVAL;
>
> - dbnc = eint->num_db_time;
> - for (i = 0; i < eint->num_db_time; i++) {
> - if (debounce <= eint->hw->db_time[i]) {
> + /*
> + * Check eint number to avoid access out-of-range
> + */
> + dbnc = ARRAY_SIZE(debounce_time) - 1;
> + for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
> + if (debounce <= debounce_time[i]) {
> dbnc = i;
> break;
> }
> @@ -449,23 +662,20 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
> if (!mtk_eint_get_mask(eint, eint_num)) {
> mtk_eint_mask(d);
> unmask = 1;
> - } else {
> + } else
> unmask = 0;
> - }
>
> - clr_bit = 0xff << eint_offset;
> - writel(clr_bit, eint->base + clr_offset);
> + clr_bit = 0xff << eint_ofset;
> + writel(clr_bit, reg + clr_ofset);
>
> - 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);
> + bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS)
> + | MTK_EINT_DBNC_SET_EN) << eint_ofset;
> + rst = MTK_EINT_DBNC_RST_BIT << eint_ofset;
> + writel(rst | bit, reg + set_ofset);
>
> /*
> - * Delay a while (more than 2T) to wait for hw debounce counter reset
> - * work correctly.
> + * Delay should be (8T @ 32k) from dbc rst to work correctly.
> */
> - udelay(1);
> if (unmask == 1)
> mtk_eint_unmask(d);
>
> @@ -473,6 +683,53 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
> }
> EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
>
> +unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
> + unsigned int eint_num)
> +{
> + unsigned int instance, index, bit;
> + void __iomem *reg;
> +
> + reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return 0;
> + }
> +
> + reg = eint->instances[instance].base +
> + (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
> +
> + bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
> +
> + return (readl(reg) & bit) ? 1 : 0;
> +}
> +
> +unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
> + unsigned int eint_num)
> +{
> + unsigned int instance, index, mask, ofset;
> + void __iomem *reg;
> +
> + reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return 0;
> + }
> +
> + reg = eint->instances[instance].base +
> + (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
> +
> + ofset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % REG_OFSET) * DB_GROUP);
> + mask = 0xf << ofset;
> +
> + return ((readl(reg) & mask) >> ofset);
> +}
> +
> int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
> {
> int irq;
> @@ -485,45 +742,209 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
> }
> EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
>
> +static const struct mtk_eint_compatible default_compat = {
> + .regs = &mtk_generic_eint_regs,
> +};
> +
> +static const struct of_device_id eint_compatible_ids[] = {
> + { }
> +};
> +
> int mtk_eint_do_init(struct mtk_eint *eint)
> {
> - int i;
> + int i, virq;
> + unsigned int size, inst = 0;
> + eint->instance_number = 1;
> + eint->total_pin_number = eint->hw->ap_num;
> +
> + for (i = 0; i < eint->total_pin_number; i++) {
> + eint->pins[i].enabled = true;
> + eint->pins[i].instance = inst;
> + eint->pins[i].index = i;
> + eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
> +
> + eint->instances[inst].pin_list[i] = i;
> + eint->instances[inst].number++;
> + }
>
> - /* If clients don't assign a specific regs, let's use generic one */
> - if (!eint->regs)
> - eint->regs = &mtk_generic_eint_regs;
> + for (i = 0; i < eint->instance_number; i++) {
> + size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
> + eint->instances[i].wake_mask =
> + devm_kzalloc(eint->dev, size, GFP_KERNEL);
> + eint->instances[i].cur_mask =
> + devm_kzalloc(eint->dev, size, GFP_KERNEL);
>
> - eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
> - sizeof(*eint->wake_mask), GFP_KERNEL);
> - if (!eint->wake_mask)
> + if (!eint->instances[i].wake_mask ||
> + !eint->instances[i].cur_mask)
> + return -ENOMEM;
> + }
> +
> + eint->comp = &default_compat;
> +
> + eint->domain = irq_domain_add_linear(eint->dev->of_node,
> + eint->total_pin_number,
> + &irq_domain_simple_ops, NULL);
> + if (!eint->domain)
> return -ENOMEM;
>
> - eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
> - sizeof(*eint->cur_mask), GFP_KERNEL);
> - if (!eint->cur_mask)
> + mtk_eint_hw_init(eint);
> + for (i = 0; i < eint->total_pin_number; i++) {
> + 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);
> +
> + global_eintc = eint;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(mtk_eint_do_init);
> +
> +int mtk_eint_do_init_v2(struct mtk_eint *eint)
> +{
> + int i, virq, matrix_number = 0;
> + struct device_node *node;
> + unsigned int ret, size, ofset;
> + unsigned int id, inst, idx, support_deb;
> +
> + const phandle *ph;
> +
> + ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
> + if (!ph) {
> + dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
> + return -ENODEV;
> + }
> +
> + node = of_find_node_by_phandle(be32_to_cpup(ph));
> + if (!node) {
> + dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
> + return -ENODEV;
> + }
> +
> + ret = of_property_read_u32(node, "mediatek,total-pin-number",
> + &eint->total_pin_number);
> + if (ret) {
> + dev_err(eint->dev,
> + "%s cannot read total-pin-number from device node.\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
> + eint->total_pin_number);
> +
> + ret = of_property_read_u32(node, "mediatek,instance-num",
> + &eint->instance_number);
> + if (ret)
> + eint->instance_number = 1; // only 1 instance in legacy chip
> +
> + size = eint->instance_number * sizeof(struct mtk_eint_instance);
> + eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
> + if (!eint->instances)
> return -ENOMEM;
>
> - eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
> - sizeof(int), GFP_KERNEL);
> - if (!eint->dual_edge)
> + size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
> + eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
> + if (!eint->pins)
> return -ENOMEM;
>
> + for (i = 0; i < eint->instance_number; i++) {
> + ret = of_property_read_string_index(node, "reg-name", i,
> + &(eint->instances[i].name));
> + if (ret) {
> + dev_info(eint->dev,
> + "%s cannot read the name of instance %d.\n",
> + __func__, i);
> + }
> +
> + eint->instances[i].base = of_iomap(node, i);
> + if (!eint->instances[i].base)
> + return -ENOMEM;
> + }
> +
> + matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
> + if (matrix_number < 0) {
> + matrix_number = eint->total_pin_number;
> + dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
> + __func__, matrix_number);
> + } else
> + dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
> + __func__, matrix_number);
> +
> + for (i = 0; i < matrix_number; i++) {
> + ofset = i * REG_OFSET;
> +
> + ret = of_property_read_u32_index(node, "mediatek,pins",
> + ofset, &id);
> + ret |= of_property_read_u32_index(node, "mediatek,pins",
> + ofset+FIRST, &inst);
> + ret |= of_property_read_u32_index(node, "mediatek,pins",
> + ofset+SECOND, &idx);
> + ret |= of_property_read_u32_index(node, "mediatek,pins",
> + ofset+THIRD, &support_deb);
> +
> + /* Legacy chip which no need to give coordinate list */
> + if (ret) {
> + id = i;
> + inst = 0;
> + idx = i;
> + support_deb = (i < MAX_BIT) ? 1 : 0;
> + }
> +
> + eint->pins[id].enabled = true;
> + eint->pins[id].instance = inst;
> + eint->pins[id].index = idx;
> + eint->pins[id].debounce = support_deb;
> +
> + eint->instances[inst].pin_list[idx] = id;
> + eint->instances[inst].number++;
> +
> +#if defined(MTK_EINT_DEBUG)
> + pin = eint->pins[id];
> + dev_info(eint->dev,
> + "EINT%u in (%u-%u), su_deb = %u",
> + id,
> + pin.instance,
> + eint->instances[inst].number,
> + pin.debounce,
> +#endif
> + }
> +
> + for (i = 0; i < eint->instance_number; i++) {
> + size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
> + eint->instances[i].wake_mask =
> + devm_kzalloc(eint->dev, size, GFP_KERNEL);
> + eint->instances[i].cur_mask =
> + devm_kzalloc(eint->dev, size, GFP_KERNEL);
> +
> + if (!eint->instances[i].wake_mask ||
> + !eint->instances[i].cur_mask)
> + return -ENOMEM;
> + }
> +
> + eint->comp = &default_compat;
> +
> + eint->irq = irq_of_parse_and_map(node, 0);
> + if (!eint->irq) {
> + dev_err(eint->dev,
> + "%s IRQ parse fail.\n", __func__);
> + return -EINVAL;
> + }
> +
> eint->domain = irq_domain_add_linear(eint->dev->of_node,
> - eint->hw->ap_num,
> + eint->total_pin_number,
> &irq_domain_simple_ops, NULL);
> if (!eint->domain)
> return -ENOMEM;
>
> - if (eint->hw->db_time) {
> - for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
> - if (eint->hw->db_time[i] == 0)
> - break;
> - eint->num_db_time = i;
> - }
> -
> mtk_eint_hw_init(eint);
> - for (i = 0; i < eint->hw->ap_num; i++) {
> - int virq = irq_create_mapping(eint->domain, i);
> + for (i = 0; i < eint->total_pin_number; i++) {
> + virq = irq_create_mapping(eint->domain, i);
>
> irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
> handle_level_irq);
> @@ -533,9 +954,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)
> irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
> eint);
>
> + global_eintc = eint;
> +
> return 0;
> }
> -EXPORT_SYMBOL_GPL(mtk_eint_do_init);
> +EXPORT_SYMBOL_GPL(mtk_eint_do_init_v2);
>
> MODULE_LICENSE("GPL v2");
> MODULE_DESCRIPTION("MediaTek EINT Driver");
> diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
> index 6139b16cd225..aa17a6073029 100644
> --- a/drivers/pinctrl/mediatek/mtk-eint.h
> +++ b/drivers/pinctrl/mediatek/mtk-eint.h
> @@ -11,6 +11,25 @@
>
> #include <linux/irqdomain.h>
>
> +#define MAX_PIN 999
> +#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)
> +#define MTK_EINT_NO_OFSET 0
> +#define MAX_BIT 32
> +#define REG_OFSET 4
> +#define REG_GROUP 5
> +#define REG_VAL 0xFFFFFFFF
> +#define DB_GROUP 8
> +#define FIRST 1
> +#define SECOND 2
> +#define THIRD 3
> +#define ARRAY_0 4
> +
> +//#define MTK_EINT_DEBUG
> +
> struct mtk_eint_regs {
> unsigned int stat;
> unsigned int ack;
> @@ -30,6 +49,36 @@ struct mtk_eint_regs {
> unsigned int dbnc_ctrl;
> unsigned int dbnc_set;
> unsigned int dbnc_clr;
> + unsigned int event;
> + unsigned int event_set;
> + unsigned int event_clr;
> + unsigned int raw_stat;
> +};
> +
> +struct mtk_eint_ops {
> + void (*ack)(struct irq_data *d);
> +};
> +
> +struct mtk_eint_compatible {
> + struct mtk_eint_ops ops;
> + const struct mtk_eint_regs *regs;
> +};
> +
> +struct mtk_eint_instance {
> + const char *name;
> + void __iomem *base;
> + unsigned int number;
> + unsigned int pin_list[MAX_PIN];
> + unsigned int *wake_mask;
> + unsigned int *cur_mask;
> +};
> +
> +struct mtk_eint_pin {
> + bool enabled;
> + unsigned int instance;
> + unsigned int index;
> + bool debounce;
> + bool dual_edge;
> };
>
> struct mtk_eint_hw {
> @@ -60,11 +109,14 @@ struct mtk_eint {
> struct irq_domain *domain;
> int irq;
>
> - int *dual_edge;
> - u32 *wake_mask;
> - u32 *cur_mask;
> -
> - /* Used to fit into various EINT device */
> + /* An array to record the coordinate, index by global EINT ID */
> + struct mtk_eint_pin *pins;
> + /* An array to record the global EINT ID, index by coordinate*/
> + struct mtk_eint_instance *instances;
> + unsigned int total_pin_number;
> + unsigned int instance_number;
> + unsigned int dump_target_eint;
> + const struct mtk_eint_compatible *comp;
> const struct mtk_eint_hw *hw;
> const struct mtk_eint_regs *regs;
> u16 num_db_time;
> @@ -74,13 +126,15 @@ struct mtk_eint {
> const struct mtk_eint_xt *gpio_xlate;
> };
>
> -#if IS_ENABLED(CONFIG_EINT_MTK)
> +#if (IS_ENABLED(CONFIG_EINT_MTK) || IS_ENABLED(CONFIG_DEVICE_MODULES_EINT_MTK))
> int mtk_eint_do_init(struct mtk_eint *eint);
> +int mtk_eint_do_init_v2(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);
> +int dump_eint_pin_status(unsigned int eint_num);
>
> #else
> static inline int mtk_eint_do_init(struct mtk_eint *eint)
> @@ -88,6 +142,11 @@ static inline int mtk_eint_do_init(struct mtk_eint *eint)
> return -EOPNOTSUPP;
> }
>
> +static inline int mtk_eint_do_init_v2(struct mtk_eint *eint)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
> {
> return -EOPNOTSUPP;
> @@ -108,5 +167,9 @@ static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
> {
> return -EOPNOTSUPP;
> }
> +static inline int dump_eint_pin_status(unsigned int eint_num)
> +{
> + return -EOPNOTSUPP;
> +}
> #endif
> #endif /* __MTK_EINT_H */
> diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
> index 54301fbba524..3740e868c650 100644
> --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
> +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
> @@ -375,33 +375,37 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
> 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;
> -
> - hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
> - if (IS_ERR(hw->eint->base)) {
> - ret = PTR_ERR(hw->eint->base);
> - goto err_free_eint;
> - }
> + if (hw->soc->eint_hw) {
> + hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
> + if (!hw->eint)
> + return -ENOMEM;
> +
> + hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
> + if (IS_ERR(hw->eint->base)) {
> + ret = PTR_ERR(hw->eint->base);
> + goto err_free_eint;
> + }
>
> - hw->eint->irq = irq_of_parse_and_map(np, 0);
> - if (!hw->eint->irq) {
> - ret = -EINVAL;
> - goto err_free_eint;
> - }
> + hw->eint->irq = irq_of_parse_and_map(np, 0);
> + if (!hw->eint->irq) {
> + ret = -EINVAL;
> + goto err_free_eint;
> + }
>
> - if (!hw->soc->eint_hw) {
> - ret = -ENODEV;
> - goto err_free_eint;
> - }
> + 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);
>
> - hw->eint->dev = &pdev->dev;
> - hw->eint->hw = hw->soc->eint_hw;
> - hw->eint->pctl = hw;
> - hw->eint->gpio_xlate = &mtk_eint_xt;
> + } else {
> + hw->eint->dev = &pdev->dev;
> + hw->eint->pctl = hw;
> + hw->eint->gpio_xlate = &mtk_eint_xt;
>
> - return mtk_eint_do_init(hw->eint);
> + return mtk_eint_do_init_v2(hw->eint);
> + }
>
> err_free_eint:
> devm_kfree(hw->dev, hw->eint);
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
2024-10-25 3:16 [PATCH] pinctrl: mediatek: add eint new design for mt8196 chang hao
2024-10-25 4:12 ` Chen-Yu Tsai
@ 2024-10-26 18:27 ` kernel test robot
2024-10-27 3:35 ` kernel test robot
2024-10-27 18:20 ` kernel test robot
3 siblings, 0 replies; 13+ messages in thread
From: kernel test robot @ 2024-10-26 18:27 UTC (permalink / raw)
To: chang hao, matthias.bgg, angelogioacchino.delregno, sean.wang,
linus.walleij
Cc: oe-kbuild-all, linux-mediatek, linux-gpio, linux-kernel,
linux-arm-kernel, Chhao Chang
Hi chang,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linusw-pinctrl/devel]
[also build test WARNING on linusw-pinctrl/for-next linus/master v6.12-rc4 next-20241025]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/chang-hao/pinctrl-mediatek-add-eint-new-design-for-mt8196/20241025-111952
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel
patch link: https://lore.kernel.org/r/20241025031814.21442-1-ot_chhao.chang%40mediatek.com
patch subject: [PATCH] pinctrl: mediatek: add eint new design for mt8196
config: arm-randconfig-r122-20241026 (https://download.01.org/0day-ci/archive/20241027/202410270252.vGIAE54G-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 14.1.0
reproduce: (https://download.01.org/0day-ci/archive/20241027/202410270252.vGIAE54G-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410270252.vGIAE54G-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/pinctrl/mediatek/mtk-eint.c:686:14: sparse: sparse: symbol 'mtk_eint_get_debounce_en' was not declared. Should it be static?
>> drivers/pinctrl/mediatek/mtk-eint.c:709:14: sparse: sparse: symbol 'mtk_eint_get_debounce_value' was not declared. Should it be static?
>> drivers/pinctrl/mediatek/mtk-eint.c:823:53: sparse: sparse: incorrect type in argument 1 (different base types) @@ expected restricted __be32 const [usertype] *p @@ got unsigned int const [usertype] *[assigned] ph @@
drivers/pinctrl/mediatek/mtk-eint.c:823:53: sparse: expected restricted __be32 const [usertype] *p
drivers/pinctrl/mediatek/mtk-eint.c:823:53: sparse: got unsigned int const [usertype] *[assigned] ph
vim +/mtk_eint_get_debounce_en +686 drivers/pinctrl/mediatek/mtk-eint.c
685
> 686 unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
687 unsigned int eint_num)
688 {
689 unsigned int instance, index, bit;
690 void __iomem *reg;
691
692 reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
693 &instance, &index);
694
695 if (!reg) {
696 dev_err(eint->dev, "%s invalid eint_num %d\n",
697 __func__, eint_num);
698 return 0;
699 }
700
701 reg = eint->instances[instance].base +
702 (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
703
704 bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
705
706 return (readl(reg) & bit) ? 1 : 0;
707 }
708
> 709 unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
710 unsigned int eint_num)
711 {
712 unsigned int instance, index, mask, ofset;
713 void __iomem *reg;
714
715 reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
716 &instance, &index);
717
718 if (!reg) {
719 dev_err(eint->dev, "%s invalid eint_num %d\n",
720 __func__, eint_num);
721 return 0;
722 }
723
724 reg = eint->instances[instance].base +
725 (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
726
727 ofset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % REG_OFSET) * DB_GROUP);
728 mask = 0xf << ofset;
729
730 return ((readl(reg) & mask) >> ofset);
731 }
732
733 int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
734 {
735 int irq;
736
737 irq = irq_find_mapping(eint->domain, eint_n);
738 if (!irq)
739 return -EINVAL;
740
741 return irq;
742 }
743 EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
744
745 static const struct mtk_eint_compatible default_compat = {
746 .regs = &mtk_generic_eint_regs,
747 };
748
749 static const struct of_device_id eint_compatible_ids[] = {
750 { }
751 };
752
753 int mtk_eint_do_init(struct mtk_eint *eint)
754 {
755 int i, virq;
756 unsigned int size, inst = 0;
757 eint->instance_number = 1;
758 eint->total_pin_number = eint->hw->ap_num;
759
760 for (i = 0; i < eint->total_pin_number; i++) {
761 eint->pins[i].enabled = true;
762 eint->pins[i].instance = inst;
763 eint->pins[i].index = i;
764 eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
765
766 eint->instances[inst].pin_list[i] = i;
767 eint->instances[inst].number++;
768 }
769
770 for (i = 0; i < eint->instance_number; i++) {
771 size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
772 eint->instances[i].wake_mask =
773 devm_kzalloc(eint->dev, size, GFP_KERNEL);
774 eint->instances[i].cur_mask =
775 devm_kzalloc(eint->dev, size, GFP_KERNEL);
776
777 if (!eint->instances[i].wake_mask ||
778 !eint->instances[i].cur_mask)
779 return -ENOMEM;
780 }
781
782 eint->comp = &default_compat;
783
784 eint->domain = irq_domain_add_linear(eint->dev->of_node,
785 eint->total_pin_number,
786 &irq_domain_simple_ops, NULL);
787 if (!eint->domain)
788 return -ENOMEM;
789
790 mtk_eint_hw_init(eint);
791 for (i = 0; i < eint->total_pin_number; i++) {
792 virq = irq_create_mapping(eint->domain, i);
793
794 irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
795 handle_level_irq);
796 irq_set_chip_data(virq, eint);
797 }
798
799 irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
800 eint);
801
802 global_eintc = eint;
803
804 return 0;
805 }
806 EXPORT_SYMBOL_GPL(mtk_eint_do_init);
807
808 int mtk_eint_do_init_v2(struct mtk_eint *eint)
809 {
810 int i, virq, matrix_number = 0;
811 struct device_node *node;
812 unsigned int ret, size, ofset;
813 unsigned int id, inst, idx, support_deb;
814
815 const phandle *ph;
816
817 ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
818 if (!ph) {
819 dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
820 return -ENODEV;
821 }
822
> 823 node = of_find_node_by_phandle(be32_to_cpup(ph));
824 if (!node) {
825 dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
826 return -ENODEV;
827 }
828
829 ret = of_property_read_u32(node, "mediatek,total-pin-number",
830 &eint->total_pin_number);
831 if (ret) {
832 dev_err(eint->dev,
833 "%s cannot read total-pin-number from device node.\n",
834 __func__);
835 return -EINVAL;
836 }
837
838 dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
839 eint->total_pin_number);
840
841 ret = of_property_read_u32(node, "mediatek,instance-num",
842 &eint->instance_number);
843 if (ret)
844 eint->instance_number = 1; // only 1 instance in legacy chip
845
846 size = eint->instance_number * sizeof(struct mtk_eint_instance);
847 eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
848 if (!eint->instances)
849 return -ENOMEM;
850
851 size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
852 eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
853 if (!eint->pins)
854 return -ENOMEM;
855
856 for (i = 0; i < eint->instance_number; i++) {
857 ret = of_property_read_string_index(node, "reg-name", i,
858 &(eint->instances[i].name));
859 if (ret) {
860 dev_info(eint->dev,
861 "%s cannot read the name of instance %d.\n",
862 __func__, i);
863 }
864
865 eint->instances[i].base = of_iomap(node, i);
866 if (!eint->instances[i].base)
867 return -ENOMEM;
868 }
869
870 matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
871 if (matrix_number < 0) {
872 matrix_number = eint->total_pin_number;
873 dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
874 __func__, matrix_number);
875 } else
876 dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
877 __func__, matrix_number);
878
879 for (i = 0; i < matrix_number; i++) {
880 ofset = i * REG_OFSET;
881
882 ret = of_property_read_u32_index(node, "mediatek,pins",
883 ofset, &id);
884 ret |= of_property_read_u32_index(node, "mediatek,pins",
885 ofset+FIRST, &inst);
886 ret |= of_property_read_u32_index(node, "mediatek,pins",
887 ofset+SECOND, &idx);
888 ret |= of_property_read_u32_index(node, "mediatek,pins",
889 ofset+THIRD, &support_deb);
890
891 /* Legacy chip which no need to give coordinate list */
892 if (ret) {
893 id = i;
894 inst = 0;
895 idx = i;
896 support_deb = (i < MAX_BIT) ? 1 : 0;
897 }
898
899 eint->pins[id].enabled = true;
900 eint->pins[id].instance = inst;
901 eint->pins[id].index = idx;
902 eint->pins[id].debounce = support_deb;
903
904 eint->instances[inst].pin_list[idx] = id;
905 eint->instances[inst].number++;
906
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
2024-10-25 3:16 [PATCH] pinctrl: mediatek: add eint new design for mt8196 chang hao
2024-10-25 4:12 ` Chen-Yu Tsai
2024-10-26 18:27 ` kernel test robot
@ 2024-10-27 3:35 ` kernel test robot
2024-10-27 18:20 ` kernel test robot
3 siblings, 0 replies; 13+ messages in thread
From: kernel test robot @ 2024-10-27 3:35 UTC (permalink / raw)
To: chang hao, matthias.bgg, angelogioacchino.delregno, sean.wang,
linus.walleij
Cc: oe-kbuild-all, linux-mediatek, linux-gpio, linux-kernel,
linux-arm-kernel, Chhao Chang
Hi chang,
kernel test robot noticed the following build errors:
[auto build test ERROR on linusw-pinctrl/devel]
[also build test ERROR on linusw-pinctrl/for-next linus/master v6.12-rc4 next-20241025]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/chang-hao/pinctrl-mediatek-add-eint-new-design-for-mt8196/20241025-111952
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel
patch link: https://lore.kernel.org/r/20241025031814.21442-1-ot_chhao.chang%40mediatek.com
patch subject: [PATCH] pinctrl: mediatek: add eint new design for mt8196
config: csky-randconfig-r071-20241027 (https://download.01.org/0day-ci/archive/20241027/202410271123.3hyFF6pg-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241027/202410271123.3hyFF6pg-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410271123.3hyFF6pg-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/pinctrl/mediatek/mtk-eint.c: In function 'mtk_eint_do_suspend':
>> drivers/pinctrl/mediatek/mtk-eint.c:588:9: error: implicit declaration of function 'dsb' [-Wimplicit-function-declaration]
588 | dsb(sy);
| ^~~
>> drivers/pinctrl/mediatek/mtk-eint.c:588:13: error: 'sy' undeclared (first use in this function); did you mean 's8'?
588 | dsb(sy);
| ^~
| s8
drivers/pinctrl/mediatek/mtk-eint.c:588:13: note: each undeclared identifier is reported only once for each function it appears in
drivers/pinctrl/mediatek/mtk-eint.c: In function 'mtk_eint_do_resume':
drivers/pinctrl/mediatek/mtk-eint.c:609:13: error: 'sy' undeclared (first use in this function); did you mean 's8'?
609 | dsb(sy);
| ^~
| s8
drivers/pinctrl/mediatek/mtk-eint.c: At top level:
drivers/pinctrl/mediatek/mtk-eint.c:686:14: warning: no previous prototype for 'mtk_eint_get_debounce_en' [-Wmissing-prototypes]
686 | unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
| ^~~~~~~~~~~~~~~~~~~~~~~~
drivers/pinctrl/mediatek/mtk-eint.c:709:14: warning: no previous prototype for 'mtk_eint_get_debounce_value' [-Wmissing-prototypes]
709 | unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/pinctrl/mediatek/mtk-eint.c:749:34: warning: 'eint_compatible_ids' defined but not used [-Wunused-const-variable=]
749 | static const struct of_device_id eint_compatible_ids[] = {
| ^~~~~~~~~~~~~~~~~~~
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for GET_FREE_REGION
Depends on [n]: SPARSEMEM [=n]
Selected by [m]:
- RESOURCE_KUNIT_TEST [=m] && RUNTIME_TESTING_MENU [=y] && KUNIT [=m]
vim +/dsb +588 drivers/pinctrl/mediatek/mtk-eint.c
572
573 int mtk_eint_do_suspend(struct mtk_eint *eint)
574 {
575 unsigned int i, j, port;
576
577 for (i = 0; i < eint->instance_number; i++) {
578 struct mtk_eint_instance inst = eint->instances[i];
579
580 for (j = 0; j < inst.number; j += MAX_BIT) {
581 port = j >> REG_GROUP;
582 writel_relaxed(~inst.wake_mask[port],
583 inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
584 writel_relaxed(inst.wake_mask[port],
585 inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
586 }
587 }
> 588 dsb(sy);
589
590 return 0;
591 }
592 EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
593
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
2024-10-25 3:16 [PATCH] pinctrl: mediatek: add eint new design for mt8196 chang hao
` (2 preceding siblings ...)
2024-10-27 3:35 ` kernel test robot
@ 2024-10-27 18:20 ` kernel test robot
3 siblings, 0 replies; 13+ messages in thread
From: kernel test robot @ 2024-10-27 18:20 UTC (permalink / raw)
To: chang hao, matthias.bgg, angelogioacchino.delregno, sean.wang,
linus.walleij
Cc: oe-kbuild-all, linux-mediatek, linux-gpio, linux-kernel,
linux-arm-kernel, Chhao Chang
Hi chang,
kernel test robot noticed the following build errors:
[auto build test ERROR on linusw-pinctrl/devel]
[also build test ERROR on linusw-pinctrl/for-next linus/master v6.12-rc4 next-20241025]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/chang-hao/pinctrl-mediatek-add-eint-new-design-for-mt8196/20241025-111952
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel
patch link: https://lore.kernel.org/r/20241025031814.21442-1-ot_chhao.chang%40mediatek.com
patch subject: [PATCH] pinctrl: mediatek: add eint new design for mt8196
config: s390-randconfig-r131-20241027 (https://download.01.org/0day-ci/archive/20241028/202410280230.KAMZK7aZ-lkp@intel.com/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce: (https://download.01.org/0day-ci/archive/20241028/202410280230.KAMZK7aZ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410280230.KAMZK7aZ-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/pinctrl/mediatek/mtk-eint.c:14:
In file included from include/linux/gpio/driver.h:8:
In file included from include/linux/irqchip/chained_irq.h:10:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:14:
In file included from arch/s390/include/asm/io.h:93:
include/asm-generic/io.h:548:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __raw_readb(PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:561:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
~~~~~~~~~~ ^
include/uapi/linux/byteorder/big_endian.h:37:59: note: expanded from macro '__le16_to_cpu'
#define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x))
^
include/uapi/linux/swab.h:102:54: note: expanded from macro '__swab16'
#define __swab16(x) (__u16)__builtin_bswap16((__u16)(x))
^
In file included from drivers/pinctrl/mediatek/mtk-eint.c:14:
In file included from include/linux/gpio/driver.h:8:
In file included from include/linux/irqchip/chained_irq.h:10:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:14:
In file included from arch/s390/include/asm/io.h:93:
include/asm-generic/io.h:574:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
~~~~~~~~~~ ^
include/uapi/linux/byteorder/big_endian.h:35:59: note: expanded from macro '__le32_to_cpu'
#define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x))
^
include/uapi/linux/swab.h:115:54: note: expanded from macro '__swab32'
#define __swab32(x) (__u32)__builtin_bswap32((__u32)(x))
^
In file included from drivers/pinctrl/mediatek/mtk-eint.c:14:
In file included from include/linux/gpio/driver.h:8:
In file included from include/linux/irqchip/chained_irq.h:10:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:14:
In file included from arch/s390/include/asm/io.h:93:
include/asm-generic/io.h:585:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writeb(value, PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:595:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:605:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:693:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
readsb(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:701:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
readsw(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:709:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
readsl(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:718:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
writesb(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:727:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
writesw(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:736:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
writesl(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
>> drivers/pinctrl/mediatek/mtk-eint.c:588:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Werror,-Wimplicit-function-declaration]
dsb(sy);
^
drivers/pinctrl/mediatek/mtk-eint.c:588:6: error: use of undeclared identifier 'sy'
dsb(sy);
^
drivers/pinctrl/mediatek/mtk-eint.c:609:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Werror,-Wimplicit-function-declaration]
dsb(sy);
^
drivers/pinctrl/mediatek/mtk-eint.c:609:6: error: use of undeclared identifier 'sy'
dsb(sy);
^
drivers/pinctrl/mediatek/mtk-eint.c:686:14: warning: no previous prototype for function 'mtk_eint_get_debounce_en' [-Wmissing-prototypes]
unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
^
drivers/pinctrl/mediatek/mtk-eint.c:686:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
^
static
drivers/pinctrl/mediatek/mtk-eint.c:709:14: warning: no previous prototype for function 'mtk_eint_get_debounce_value' [-Wmissing-prototypes]
unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
^
drivers/pinctrl/mediatek/mtk-eint.c:709:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
^
static
14 warnings and 4 errors generated.
vim +/dsb +588 drivers/pinctrl/mediatek/mtk-eint.c
572
573 int mtk_eint_do_suspend(struct mtk_eint *eint)
574 {
575 unsigned int i, j, port;
576
577 for (i = 0; i < eint->instance_number; i++) {
578 struct mtk_eint_instance inst = eint->instances[i];
579
580 for (j = 0; j < inst.number; j += MAX_BIT) {
581 port = j >> REG_GROUP;
582 writel_relaxed(~inst.wake_mask[port],
583 inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
584 writel_relaxed(inst.wake_mask[port],
585 inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
586 }
587 }
> 588 dsb(sy);
589
590 return 0;
591 }
592 EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
593
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH] pinctrl: mediatek: add eint new design for mt8196
@ 2024-12-02 8:50 chang hao
2024-12-02 11:50 ` kernel test robot
2024-12-02 12:41 ` kernel test robot
0 siblings, 2 replies; 13+ messages in thread
From: chang hao @ 2024-12-02 8:50 UTC (permalink / raw)
To: matthias.bgg, angelogioacchino.delregno, sean.wang, linus.walleij
Cc: linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel,
Chhao Chang
From: Chhao Chang <ot_chhao.chang@mediatek.com>
Change 1: change EINT from 1 address to 5 addresses,
Eint number is stored on each base.
Change 2: Compatible with 1 address design
Signed-off-by: Chhao Chang <ot_chhao.chang@mediatek.com>
---
drivers/pinctrl/mediatek/mtk-eint.c | 976 ++++++++++++++----
drivers/pinctrl/mediatek/mtk-eint.h | 87 +-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 50 +-
3 files changed, 877 insertions(+), 236 deletions(-)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 27f0a54e12bf..2d13e36017ae 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -1,21 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2014-2018 MediaTek Inc.
-
+// Copyright (c) 2014-2024 MediaTek Inc.
/*
* Library for MediaTek External Interrupt Support
*
* Author: Maoguang Meng <maoguang.meng@mediatek.com>
- * Sean Wang <sean.wang@mediatek.com>
- *
+ * Sean Wang <sean.wang@mediatek.com>
+ * Chhao Chang <ot_chhao.chang@mediatek.com>
*/
+#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
+#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
@@ -23,10 +26,14 @@
#define MTK_EINT_EDGE_SENSITIVE 0
#define MTK_EINT_LEVEL_SENSITIVE 1
-#define MTK_EINT_DBNC_SET_DBNC_BITS 4
-#define MTK_EINT_DBNC_MAX 16
-#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
-#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
+#define MTK_EINT_DBNC_SET_DBNC_BITS 4
+#define MTK_EINT_DBNC_MAX 16
+#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
+#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
+
+#define MTK_EINT_NO_OFFSET 0
+
+static struct mtk_eint *global_eintc;
static const struct mtk_eint_regs mtk_generic_eint_regs = {
.stat = 0x000,
@@ -47,6 +54,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
+ .event = 0x800,
+ .event_set = 0x840,
+ .event_clr = 0x880,
+ .raw_stat = 0xa00,
};
const unsigned int debounce_time_mt2701[] = {
@@ -64,60 +75,122 @@ const unsigned int debounce_time_mt6795[] = {
};
EXPORT_SYMBOL_GPL(debounce_time_mt6795);
+/*
+ * Return the iomem of specific register offset and decode the coordinate
+ * (instance, index) from global eint number.
+ * If return NULL, then it must be either out-of-range or do-not-support.
+ */
static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
unsigned int eint_num,
- unsigned int offset)
+ unsigned int offset,
+ unsigned int *instance,
+ unsigned int *index)
{
- unsigned int eint_base = 0;
void __iomem *reg;
- if (eint_num >= eint->hw->ap_num)
- eint_base = eint->hw->ap_num;
+ if (eint_num >= eint->total_pin_number ||
+ !eint->pins[eint_num].enabled) {
+ WARN_ON(1);
+ return NULL;
+ }
- reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+ *instance = eint->pins[eint_num].instance;
+ *index = eint->pins[eint_num].index;
+ reg = eint->instances[*instance].base + offset + (*index / 32 * 4);
return reg;
}
+/*
+ * Generate helper function to access property register of a dedicate pin.
+ */
+#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFFSET) \
+static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
+ unsigned int eint_num) \
+{ \
+ unsigned int instance, index; \
+ void __iomem *reg = mtk_eint_get_offset(eint, eint_num, \
+ _OFFSET, \
+ &instance, &index); \
+ unsigned int bit = BIT(index & 0x1f);\
+\
+ if (!reg) { \
+ dev_err(eint->dev, "%s invalid eint_num %d\n", \
+ __func__, eint_num); \
+ return 0;\
+ } \
+\
+ return !!(readl(reg) & bit); \
+}
+
+DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
+DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
+DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
+DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
+DEFINE_EINT_GET_FUNCTION(soft, eint->comp->regs->soft);
+DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
+
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);
+ unsigned int instance, index;
void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
- eint->regs->sens);
+ eint->comp->regs->sens,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
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)
+ if (eint->pins[eint_num].debounce &&
+ sens != MTK_EINT_EDGE_SENSITIVE)
return 1;
else
return 0;
}
-static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)
{
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);
+ unsigned int instance, index, mask, port;
+ void __iomem *reg;
- curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+ reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ mask = BIT(index & 0x1f);
+ port = index >> 5;
+ reg = eint->instances[instance].base + port * 4;
+
+ curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, eint_num);
do {
start_level = curr_level;
if (start_level)
- reg_offset = eint->regs->pol_clr;
+ reg_offset = eint->comp->regs->pol_clr;
else
- reg_offset = eint->regs->pol_set;
+ reg_offset = eint->comp->regs->pol_set;
+
writel(mask, reg + reg_offset);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
- hwirq);
+ eint_num);
} while (start_level != curr_level);
return start_level;
@@ -126,11 +199,19 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
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);
+ unsigned int instance, index;
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
- eint->regs->mask_set);
+ eint->comp->regs->mask_set,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] &= ~mask;
+ eint->instances[instance].cur_mask[index >> 5] &= ~mask;
writel(mask, reg);
}
@@ -138,43 +219,123 @@ static void mtk_eint_mask(struct irq_data *d)
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);
+ unsigned int instance, index;
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
- eint->regs->mask_clr);
+ eint->comp->regs->mask_clr,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] |= mask;
+ eint->instances[instance].cur_mask[index >> 5] |= mask;
writel(mask, reg);
- if (eint->dual_edge[d->hwirq])
+ if (eint->pins[d->hwirq].dual_edge)
mtk_eint_flip_edge(eint, d->hwirq);
}
-static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
- unsigned int eint_num)
+/*
+ * We need to do extra effort to clear edge-triggered EINT
+ * which located in eint_c due to hw design limitation.
+ */
+void mt6983_eint_ack(struct irq_data *d)
{
- unsigned int bit = BIT(eint_num % 32);
- void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
- eint->regs->mask);
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ unsigned int instance, index;
+ void __iomem *sens_reg;
+ void __iomem *ack_reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->sens,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!ack_reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- return !!(readl(reg) & bit);
+ if (instance == 4) {
+ sens_reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->sens_clr,
+ &instance, &index);
+ writel(bit, sens_reg);
+ sens_reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->sens_set,
+ &instance, &index);
+ writel(bit, sens_reg);
+ } else {
+ writel(bit, ack_reg);
+ }
}
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);
+ unsigned int instance, index;
+ void __iomem *reg;
+ unsigned int bit;
- writel(mask, reg);
+ if (eint->comp->ops.ack) {
+ eint->comp->ops.ack(d);
+ } else {
+ reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->ack,
+ &instance, &index);
+ bit = BIT(index & 0x1f);
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
+
+ writel(bit, reg);
+ }
+}
+
+static void mtk_eint_soft_set(struct mtk_eint *eint, unsigned int eint_num)
+{
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
+ eint->comp->regs->soft_set,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
+
+ writel(bit, reg);
+}
+
+static void mtk_eint_soft_clr(struct mtk_eint *eint, unsigned int eint_num)
+{
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
+ eint->comp->regs->soft_clr,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
+
+ writel(bit, 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);
- bool masked;
- u32 mask = BIT(d->hwirq & 0x1f);
+ u32 mask;
+ unsigned int instance, index;
void __iomem *reg;
if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
@@ -186,36 +347,42 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
}
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- eint->dual_edge[d->hwirq] = 1;
+ eint->pins[d->hwirq].dual_edge = 1;
else
- eint->dual_edge[d->hwirq] = 0;
+ eint->pins[d->hwirq].dual_edge = 0;
- if (!mtk_eint_get_mask(eint, d->hwirq)) {
- mtk_eint_mask(d);
- masked = false;
- } else {
- masked = true;
- }
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->pol_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->pol_set,
+ &instance, &index);
- 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);
- }
+ mask = BIT(index & 0x1f);
+ 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 (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->sens_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->comp->regs->sens_set,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
}
- mtk_eint_ack(d);
- if (!masked)
- mtk_eint_unmask(d);
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (eint->pins[d->hwirq].dual_edge)
+ mtk_eint_flip_edge(eint, d->hwirq);
return 0;
}
@@ -223,30 +390,28 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
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;
+ unsigned int instance, index, shift, port;
+ void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
+ MTK_EINT_NO_OFFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
+ }
+
+ shift = index & 0x1f;
+ port = index >> 5;
if (on)
- eint->wake_mask[reg] |= BIT(shift);
+ eint->instances[instance].wake_mask[port] |= BIT(shift);
else
- eint->wake_mask[reg] &= ~BIT(shift);
+ eint->instances[instance].wake_mask[port] &= ~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 int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -258,23 +423,25 @@ static int mtk_eint_irq_request_resources(struct irq_data *d)
&gpio_n, &gpio_c);
if (err < 0) {
dev_err(eint->dev, "Can not find pin\n");
- return err;
+ goto err_out;
}
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;
+ goto err_out;
}
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;
+ goto err_out;
}
return 0;
+err_out:
+ return err;
}
static void mtk_eint_irq_release_resources(struct irq_data *d)
@@ -290,7 +457,7 @@ static void mtk_eint_irq_release_resources(struct irq_data *d)
}
static struct irq_chip mtk_eint_irq_chip = {
- .name = "mt-eint",
+ .name = "mtk-eint",
.irq_disable = mtk_eint_mask,
.irq_mask = mtk_eint_mask,
.irq_unmask = mtk_eint_unmask,
@@ -301,35 +468,53 @@ static struct irq_chip mtk_eint_irq_chip = {
.irq_release_resources = mtk_eint_irq_release_resources,
};
+/*
+ * Configure all EINT pins as domain 0, which only belongs to AP.
+ */
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
- void __iomem *dom_en = eint->base + eint->regs->dom_en;
- void __iomem *mask_set = eint->base + eint->regs->mask_set;
- unsigned int i;
-
- for (i = 0; i < eint->hw->ap_num; i += 32) {
- writel(0xffffffff, dom_en);
- writel(0xffffffff, mask_set);
- dom_en += 4;
- mask_set += 4;
+ void __iomem *dom, *eevt;
+ unsigned int i, j;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ dom = eint->instances[i].base + eint->comp->regs->dom_en;
+ eevt = eint->instances[i].base + eint->comp->regs->event_clr;
+ for (j = 0; j < eint->instances[i].number; j += 32) {
+ writel(0xffffffff, dom);
+ writel(0xffffffff, eevt);
+ dom += 4;
+ eevt += 4;
+ }
}
return 0;
}
static inline void
-mtk_eint_debounce_process(struct mtk_eint *eint, int index)
+mtk_eint_debounce_process(struct mtk_eint *eint, int eint_num)
{
unsigned int rst, ctrl_offset;
unsigned int bit, dbnc;
+ unsigned int instance, index;
+ void __iomem *reg;
- ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl;
- dbnc = readl(eint->base + ctrl_offset);
+ reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
+
+ ctrl_offset = (index / 4) * 4 + eint->comp->regs->dbnc_ctrl;
+ dbnc = readl(eint->instances[instance].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;
+ ctrl_offset = (index / 4) * 4 + eint->comp->regs->dbnc_set;
rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8);
- writel(rst, eint->base + ctrl_offset);
+ writel(rst, eint->instances[instance].base + ctrl_offset);
}
}
@@ -337,65 +522,66 @@ 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, mask_offset, index;
- void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
- int dual_edge, start_level, curr_level;
+ unsigned int status, i, j;
+ int shift, port, eint_num, virq;
+ unsigned int dual_edge, start_level, curr_level;
+ struct mtk_eint_instance eint_instance;
+ void __iomem *addr;
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);
- mask_offset = eint_num >> 5;
- index = eint_num + offset;
- status &= ~BIT(offset);
-
- /*
- * If we get an interrupt on pin that was only required
- * for wake (but no real interrupt requested), mask the
- * interrupt (as would mtk_eint_resume do anyway later
- * in the resume sequence).
- */
- if (eint->wake_mask[mask_offset] & BIT(offset) &&
- !(eint->cur_mask[mask_offset] & BIT(offset))) {
- writel_relaxed(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->mask_set);
- }
- 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);
+ for (i = 0; i < eint->instance_number; i++) {
+ eint_instance = eint->instances[i];
- start_level =
- eint->gpio_xlate->get_gpio_state(eint->pctl,
- index);
- }
+ /* Iterate all pins by port */
+ for (j = 0; j < eint_instance.number; j += 32) {
+ port = j >> 5;
+ status = readl(eint_instance.base + port * 4 +
+ eint->comp->regs->stat);
+ while (status) {
+ shift = __ffs(status);
+ status &= ~BIT(shift);
- generic_handle_domain_irq(eint->domain, index);
-
- if (dual_edge) {
- curr_level = mtk_eint_flip_edge(eint, index);
+ eint_num = eint->instances[i].pin_list[shift + j];
+ virq = irq_find_mapping(eint->domain, eint_num);
/*
- * If level changed, we might lost one edge
- * interrupt, raised it through soft-irq.
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
*/
- if (start_level != curr_level)
- writel(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->soft_set);
+ if (eint->instances[i].wake_mask[port] & BIT(shift) &&
+ !(eint->instances[i].cur_mask[port] & BIT(shift))) {
+ addr = eint_instance.base + port * 4 +
+ eint->comp->regs->mask_set;
+ writel_relaxed(BIT(shift), addr);
+ }
+
+ dual_edge = eint->pins[eint_num].dual_edge;
+ if (dual_edge)
+ start_level =
+ eint->gpio_xlate->get_gpio_state(eint->pctl,
+ eint_num);
+
+ generic_handle_irq(virq);
+
+ if (dual_edge) {
+ curr_level = mtk_eint_flip_edge(eint, eint_num);
+
+ /*
+ * If level changed, we might lost one edge
+ * interrupt, raised it through soft-irq.
+ */
+ if (start_level != curr_level)
+ mtk_eint_soft_set(eint, eint_num);
+
+ mtk_eint_soft_clr(eint, eint_num);
+ }
+
+ if (eint->pins[eint_num].debounce)
+ mtk_eint_debounce_process(eint, eint_num);
}
-
- if (index < eint->hw->db_cnt)
- mtk_eint_debounce_process(eint, index);
}
}
chained_irq_exit(chip, desc);
@@ -403,7 +589,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += 32) {
+ port = j >> 5;
+ writel_relaxed(~inst.wake_mask[port],
+ inst.base + port * 4 + eint->comp->regs->mask_set);
+ writel_relaxed(inst.wake_mask[port],
+ inst.base + port * 4 + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -411,7 +610,20 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
int mtk_eint_do_resume(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += 32) {
+ port = j >> 5;
+ writel_relaxed(~inst.cur_mask[port],
+ inst.base + port * 4 + eint->comp->regs->mask_set);
+ writel_relaxed(inst.cur_mask[port],
+ inst.base + port * 4 + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -423,24 +635,42 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
int virq, eint_offset;
unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
dbnc;
+ static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
+ 20000, 40000, 80000, 160000, 320000, 640000 };
struct irq_data *d;
+ unsigned int instance, index;
+ void __iomem *reg;
- if (!eint->hw->db_time)
- return -EOPNOTSUPP;
+ /*
+ * Due to different number of bit field, we only decode
+ * the coordinate here, instead of get the VA.
+ */
+ reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, eint_num);
+ return 0;
+ }
virq = irq_find_mapping(eint->domain, eint_num);
- eint_offset = (eint_num % 4) * 8;
+ eint_offset = (index % 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;
+ reg = eint->instances[instance].base;
+ set_offset = (index / 4) * 4 + eint->comp->regs->dbnc_set;
+ clr_offset = (index / 4) * 4 + eint->comp->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
- dbnc = eint->num_db_time;
- for (i = 0; i < eint->num_db_time; i++) {
- if (debounce <= eint->hw->db_time[i]) {
+ /*
+ * Check eint number to avoid access out-of-range
+ */
+ dbnc = ARRAY_SIZE(debounce_time) - 1;
+ for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+ if (debounce <= debounce_time[i]) {
dbnc = i;
break;
}
@@ -454,18 +684,16 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
}
clr_bit = 0xff << eint_offset;
- writel(clr_bit, eint->base + clr_offset);
+ writel(clr_bit, reg + clr_offset);
- bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) <<
- eint_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);
+ writel(rst | bit, reg + set_offset);
+
+ /* Delay should be (8T @ 32k) from dbc rst to work correctly. */
+ udelay(250);
- /*
- * Delay a while (more than 2T) to wait for hw debounce counter reset
- * work correctly.
- */
- udelay(1);
if (unmask == 1)
mtk_eint_unmask(d);
@@ -473,6 +701,53 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
}
EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
+unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, bit;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / 4) * 4 + eint->comp->regs->dbnc_ctrl;
+
+ bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
+
+ return (readl(reg) & bit) ? 1 : 0;
+}
+
+unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, mask, offset;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / 4) * 4 + eint->comp->regs->dbnc_ctrl;
+
+ offset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % 4) * 8);
+ mask = 0xf << offset;
+
+ return ((readl(reg) & mask) >> offset);
+}
+
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
int irq;
@@ -485,44 +760,348 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
}
EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
+/*
+ * Dump the properties/states of the specific EINT pin.
+ * @eint_num: the global EINT number.
+ * @buf: the pointer of a string buffer.
+ * @buf_size: the size of the buffer.
+ *
+ * If the return value < 0, it means that the @eint_num is invalid;
+ * Otherwise, return 0;
+ */
+int dump_eint_pin_status(unsigned int eint_num, char *buf, unsigned int buf_size)
+{
+ unsigned int len = 0, enabled, stat, raw_stat, soft, mask, sens, pol,
+ deb_en, deb_val;
+
+ if (eint_num < 0 || eint_num >= global_eintc->total_pin_number)
+ return -ENODEV;
+
+ enabled = global_eintc->pins[eint_num].enabled;
+ stat = mtk_eint_get_stat(global_eintc, eint_num);
+ raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
+ soft = mtk_eint_get_soft(global_eintc, eint_num);
+ mask = mtk_eint_get_mask(global_eintc, eint_num);
+ sens = mtk_eint_get_sens(global_eintc, eint_num);
+ pol = mtk_eint_get_pol(global_eintc, eint_num);
+
+ len += snprintf(buf + len, buf_size - len,
+ "%s=%u(%s)\n%s=%s_%s\n%s=%u\n%s=%u\n%s=%u\n%s=%u\n",
+ "Pin", eint_num, enabled ? "enabled" : "disabled",
+ "Type", (sens == 1) ? "level" : "edge",
+ (pol == 1) ? "high" : "low",
+ "Pending", stat,
+ "Raw", raw_stat,
+ "Soft", soft,
+ "Mask", mask);
+
+ if (mtk_eint_can_en_debounce(global_eintc, eint_num)) {
+ deb_en = mtk_eint_get_debounce_en(global_eintc, eint_num);
+ deb_val = mtk_eint_get_debounce_value(global_eintc, eint_num);
+
+ len += snprintf(buf + len, buf_size - len,
+ "Support debounce, %s=%u, %s=%u\n",
+ "enable", deb_en,
+ "setting", deb_val);
+ } else {
+ len += snprintf(buf + len, buf_size - len,
+ "Not support debounce\n");
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dump_eint_pin_status);
+
+static ssize_t eintc_status_show(struct device_driver *driver, char *buf)
+{
+ struct mtk_eint *eint = global_eintc;
+ unsigned int i, j, len = 0,
+ instance_num = eint->instance_number;
+
+ len += snprintf(buf + len, PAGE_SIZE - len, "=====EINTC Dump=====\n");
+
+ for (i = 0; i < instance_num; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "Instance %d name=%s with %u pins\n",
+ i, inst.name, inst.number);
+
+ for (j = 0; j < inst.number; j++)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%d ", inst.pin_list[j]);
+
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ }
+
+ return strlen(buf);
+}
+
+static DRIVER_ATTR_RO(eintc_status);
+
+static ssize_t eint_pin_status_show(struct device_driver *driver, char *buf)
+{
+ struct mtk_eint *eint = global_eintc;
+ unsigned int len = 0;
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "=====EINT Pin Dump=====\n");
+
+ dump_eint_pin_status(eint->dump_target_eint,
+ buf + len, PAGE_SIZE - len);
+
+ return strlen(buf);
+}
+
+static ssize_t eint_pin_status_store(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ int eint_num, ret;
+
+ ret = kstrtouint(buf, 10, &eint_num);
+
+ if (ret || eint_num >= global_eintc->total_pin_number) {
+ dev_err(global_eintc->dev,
+ "%s invalid input: %s.\n", __func__, buf);
+ goto err_out;
+ }
+
+ global_eintc->dump_target_eint = (unsigned int)eint_num;
+
+err_out:
+ return count;
+}
+
+static DRIVER_ATTR_RW(eint_pin_status);
+
+static const struct mtk_eint_compatible default_compat = {
+ .regs = &mtk_generic_eint_regs,
+};
+
int mtk_eint_do_init(struct mtk_eint *eint)
{
- int i;
+ int i, virq;
+ unsigned int ret, size, inst = 0;
- /* If clients don't assign a specific regs, let's use generic one */
- if (!eint->regs)
- eint->regs = &mtk_generic_eint_regs;
+ eint->instance_number = 1;
+ eint->total_pin_number = eint->hw->ap_num;
- eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->wake_mask), GFP_KERNEL);
- if (!eint->wake_mask)
- return -ENOMEM;
+ dev_info(eint->dev, "%s read ap_num: %u\n", __func__, eint->hw->ap_num);
- eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->cur_mask), GFP_KERNEL);
- if (!eint->cur_mask)
+ size = eint->instance_number * sizeof(struct mtk_eint_instance);
+ eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->instances)
return -ENOMEM;
- eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
- sizeof(int), GFP_KERNEL);
- if (!eint->dual_edge)
+ size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
+ eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->pins)
return -ENOMEM;
+ for (i = 0; i < eint->total_pin_number; i++) {
+ eint->pins[i].enabled = true;
+ eint->pins[i].instance = inst;
+ eint->pins[i].index = i;
+ eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
+
+ eint->instances[inst].pin_list[i] = i;
+ eint->instances[inst].number++;
+ }
+
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / 32 + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
eint->domain = irq_domain_add_linear(eint->dev->of_node,
- eint->hw->ap_num,
+ eint->total_pin_number,
&irq_domain_simple_ops, NULL);
if (!eint->domain)
return -ENOMEM;
- if (eint->hw->db_time) {
- for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
- if (eint->hw->db_time[i] == 0)
- break;
- eint->num_db_time = i;
+ eint->instances[inst].base = eint->base;
+
+ mtk_eint_hw_init(eint);
+
+ for (i = 0; i < eint->total_pin_number; i++) {
+ 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);
+
+ ret = driver_create_file(eint->dev->driver,
+ &driver_attr_eintc_status);
+
+ ret |= driver_create_file(eint->dev->driver,
+ &driver_attr_eint_pin_status);
+
+ if (ret)
+ dev_err(eint->dev, "%s create sysfs files failed.\n", __func__);
+
+ global_eintc = eint;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+
+int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ int i, matrix_number = 0;
+ struct device_node *node;
+ unsigned int ret, size, offset;
+ unsigned int id, inst, idx, support_deb;
+
+ const phandle *ph;
+
+#if defined(MTK_EINT_DEBUG)
+ struct mtk_eint_pin pin;
+#endif
+
+ ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
+ if (!ph) {
+ dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
+ return -ENODEV;
+ }
+
+ node = of_find_node_by_phandle(be32_to_cpup(ph));
+ if (!node) {
+ dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(node, "mediatek,total-pin-number",
+ &eint->total_pin_number);
+ if (ret) {
+ dev_err(eint->dev, "%s Get total pin Fail.\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_info(eint->dev, "%s eint total pins:%u.\n",
+ __func__, eint->total_pin_number);
+
+ ret = of_property_read_u32(node, "mediatek,instance-num",
+ &eint->instance_number);
+ if (ret)
+ eint->instance_number = 1;
+
+ size = eint->instance_number * sizeof(struct mtk_eint_instance);
+ eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->instances)
+ return -ENOMEM;
+
+ size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
+ eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->pins)
+ return -ENOMEM;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ ret = of_property_read_string_index(node, "reg-name", i,
+ &(eint->instances[i].name));
+ if (ret) {
+ dev_info(eint->dev,
+ "%s cannot read the name of instance %d.\n",
+ __func__, i);
+ }
+
+ eint->instances[i].base = of_iomap(node, i);
+ if (!eint->instances[i].base)
+ return -ENOMEM;
+ }
+
+ matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / 4;
+ if (matrix_number < 0) {
+ matrix_number = eint->total_pin_number;
+ dev_info(eint->dev, "%s eint in legacy mode, matrix number is %u.\n",
+ __func__, matrix_number);
+ } else {
+ dev_info(eint->dev, "%s eint in new mode, matrix number is %u.\n",
+ __func__, matrix_number);
+ }
+
+ for (i = 0; i < matrix_number ; i++) {
+ offset = i * 4;
+
+ ret = of_property_read_u32_index(node, "mediatek,pins",
+ offset, &id);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ offset + 1, &inst);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ offset + 2, &idx);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ offset + 3, &support_deb);
+
+ /* Legacy chip which no need to give coordinate list */
+ if (ret) {
+ id = i;
+ inst = 0;
+ idx = i;
+ support_deb = (i < MTK_EINT_DBNC_MAX) ? 1 : 0;
+ }
+
+ eint->pins[id].enabled = true;
+ eint->pins[id].instance = inst;
+ eint->pins[id].index = idx;
+ eint->pins[id].debounce = support_deb;
+
+ eint->instances[inst].pin_list[idx] = id;
+ eint->instances[inst].number++;
+
+#if defined(MTK_EINT_DEBUG)
+ pin = eint->pins[id];
+ dev_info(eint->dev,
+ "EINT%u in (%u-%u, %u), deb = %u. %u",
+ id,
+ pin.instance,
+ eint->instances[inst].number,
+ pin.index,
+ pin.debounce,
+ eint->instances[pin.instance].pin_list[pin.index]);
+#endif
+ }
+
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / 32 + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
}
+ eint->comp = &default_compat;
+
+ eint->irq = irq_of_parse_and_map(node, 0);
+ if (!eint->irq) {
+ dev_err(eint->dev,
+ "%s IRQ parse fail.\n", __func__);
+ return -EINVAL;
+ }
+
+ eint->domain = irq_domain_add_linear(eint->dev->of_node,
+ eint->total_pin_number,
+ &irq_domain_simple_ops, NULL);
+ if (!eint->domain)
+ return -ENOMEM;
+
mtk_eint_hw_init(eint);
- for (i = 0; i < eint->hw->ap_num; i++) {
+ for (i = 0; i < eint->total_pin_number; i++) {
int virq = irq_create_mapping(eint->domain, i);
irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
@@ -533,9 +1112,20 @@ int mtk_eint_do_init(struct mtk_eint *eint)
irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
eint);
+ ret = driver_create_file(eint->dev->driver,
+ &driver_attr_eintc_status);
+
+ ret |= driver_create_file(eint->dev->driver,
+ &driver_attr_eint_pin_status);
+
+ if (ret)
+ dev_err(eint->dev, "%s create sysfs files failed.\n", __func__);
+
+ global_eintc = eint;
+
return 0;
}
-EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+EXPORT_SYMBOL_GPL(mtk_eint_do_init_v2);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MediaTek EINT Driver");
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 6139b16cd225..30be50308b44 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -1,16 +1,19 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2014-2018 MediaTek Inc.
+ * Copyright (C) 2014-2024 MediaTek Inc.
*
* Author: Maoguang Meng <maoguang.meng@mediatek.com>
- * Sean Wang <sean.wang@mediatek.com>
- *
+ * Sean Wang <sean.wang@mediatek.com>
+ * Chhao Chang <ot_chhao.chang@mediatek.com>
*/
#ifndef __MTK_EINT_H
#define __MTK_EINT_H
#include <linux/irqdomain.h>
+#define MAX_PIN 256
+//#define MTK_EINT_DEBUG
+
struct mtk_eint_regs {
unsigned int stat;
unsigned int ack;
@@ -30,19 +33,37 @@ struct mtk_eint_regs {
unsigned int dbnc_ctrl;
unsigned int dbnc_set;
unsigned int dbnc_clr;
+ unsigned int event;
+ unsigned int event_set;
+ unsigned int event_clr;
+ unsigned int raw_stat;
};
-struct mtk_eint_hw {
- u8 port_mask;
- u8 ports;
- unsigned int ap_num;
- unsigned int db_cnt;
- const unsigned int *db_time;
+struct mtk_eint_ops {
+ void (*ack)(struct irq_data *d);
};
-extern const unsigned int debounce_time_mt2701[];
-extern const unsigned int debounce_time_mt6765[];
-extern const unsigned int debounce_time_mt6795[];
+struct mtk_eint_compatible {
+ struct mtk_eint_ops ops;
+ const struct mtk_eint_regs *regs;
+};
+
+struct mtk_eint_pin {
+ bool enabled;
+ u8 instance;
+ u8 index;
+ bool debounce;
+ bool dual_edge;
+};
+
+struct mtk_eint_instance {
+ const char *name;
+ void __iomem *base;
+ unsigned int number;
+ u16 pin_list[MAX_PIN];
+ unsigned int *wake_mask;
+ unsigned int *cur_mask;
+};
struct mtk_eint;
@@ -54,33 +75,49 @@ struct mtk_eint_xt {
int (*set_gpio_as_eint)(void *data, unsigned long eint_n);
};
+struct mtk_eint_hw {
+ u8 port_mask;
+ u8 ports;
+ unsigned int ap_num;
+ unsigned int db_cnt;
+ const unsigned int *db_time;
+};
+
+extern const unsigned int debounce_time_mt2701[];
+extern const unsigned int debounce_time_mt6765[];
+extern const unsigned int debounce_time_mt6795[];
+
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 */
+ /* An array to record the coordinate, index by global EINT ID */
+ struct mtk_eint_pin *pins;
+ /* An array to record the global EINT ID, index by coordinate */
+ struct mtk_eint_instance *instances;
+ unsigned int total_pin_number;
+ unsigned int instance_number;
+ unsigned int dump_target_eint;
+ const struct mtk_eint_compatible *comp;
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
- u16 num_db_time;
/* Used to fit into various pinctrl device */
void *pctl;
const struct mtk_eint_xt *gpio_xlate;
};
-#if IS_ENABLED(CONFIG_EINT_MTK)
+#if (IS_ENABLED(CONFIG_EINT_MTK) || IS_ENABLED(CONFIG_DEVICE_MODULES_EINT_MTK))
int mtk_eint_do_init(struct mtk_eint *eint);
+int mtk_eint_do_init_v2(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);
+int dump_eint_pin_status(unsigned int eint_num, char *buf, unsigned int buf_size);
#else
static inline int mtk_eint_do_init(struct mtk_eint *eint)
@@ -88,6 +125,11 @@ static inline int mtk_eint_do_init(struct mtk_eint *eint)
return -EOPNOTSUPP;
}
+static inline int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
@@ -108,5 +150,10 @@ static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
return -EOPNOTSUPP;
}
+
+static inline int dump_eint_pin_status(unsigned int eint_num)
+{
+ return -EOPNOTSUPP;
+}
#endif
#endif /* __MTK_EINT_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index 54301fbba524..59d5ca2405f3 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -375,33 +375,37 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
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;
-
- hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
- if (IS_ERR(hw->eint->base)) {
- ret = PTR_ERR(hw->eint->base);
- goto err_free_eint;
- }
+ if (hw->soc->eint_hw) {
+ hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
+ if (!hw->eint)
+ return -ENOMEM;
+
+ hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
+ if (IS_ERR(hw->eint->base)) {
+ ret = PTR_ERR(hw->eint->base);
+ goto err_free_eint;
+ }
- hw->eint->irq = irq_of_parse_and_map(np, 0);
- if (!hw->eint->irq) {
- ret = -EINVAL;
- goto err_free_eint;
- }
+ hw->eint->irq = irq_of_parse_and_map(np, 0);
+ if (!hw->eint->irq) {
+ ret = -EINVAL;
+ goto err_free_eint;
+ }
- if (!hw->soc->eint_hw) {
- ret = -ENODEV;
- goto err_free_eint;
- }
+ 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);
- hw->eint->dev = &pdev->dev;
- hw->eint->hw = hw->soc->eint_hw;
- hw->eint->pctl = hw;
- hw->eint->gpio_xlate = &mtk_eint_xt;
+ } else {
+ hw->eint->dev = &pdev->dev;
+ hw->eint->pctl = hw;
+ hw->eint->gpio_xlate = &mtk_eint_xt;
- return mtk_eint_do_init(hw->eint);
+ return mtk_eint_do_init_v2(hw->eint);
+ }
err_free_eint:
devm_kfree(hw->dev, hw->eint);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
2024-12-02 8:50 chang hao
@ 2024-12-02 11:50 ` kernel test robot
2024-12-02 12:41 ` kernel test robot
1 sibling, 0 replies; 13+ messages in thread
From: kernel test robot @ 2024-12-02 11:50 UTC (permalink / raw)
To: chang hao, matthias.bgg, angelogioacchino.delregno, sean.wang,
linus.walleij
Cc: llvm, oe-kbuild-all, linux-mediatek, linux-gpio, linux-kernel,
linux-arm-kernel, Chhao Chang
Hi chang,
kernel test robot noticed the following build errors:
[auto build test ERROR on linusw-pinctrl/devel]
[also build test ERROR on linusw-pinctrl/for-next linus/master v6.13-rc1 next-20241128]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/chang-hao/pinctrl-mediatek-add-eint-new-design-for-mt8196/20241202-165544
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel
patch link: https://lore.kernel.org/r/20241202085024.25375-1-ot_chhao.chang%40mediatek.com
patch subject: [PATCH] pinctrl: mediatek: add eint new design for mt8196
config: x86_64-buildonly-randconfig-004-20241202 (https://download.01.org/0day-ci/archive/20241202/202412021959.txWIlGI0-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241202/202412021959.txWIlGI0-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202412021959.txWIlGI0-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
>> drivers/pinctrl/mediatek/mtk-eint.c:246:6: warning: no previous prototype for function 'mt6983_eint_ack' [-Wmissing-prototypes]
246 | void mt6983_eint_ack(struct irq_data *d)
| ^
drivers/pinctrl/mediatek/mtk-eint.c:246:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
246 | void mt6983_eint_ack(struct irq_data *d)
| ^
| static
>> drivers/pinctrl/mediatek/mtk-eint.c:605:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
605 | dsb(sy);
| ^
>> drivers/pinctrl/mediatek/mtk-eint.c:605:6: error: use of undeclared identifier 'sy'
605 | dsb(sy);
| ^
drivers/pinctrl/mediatek/mtk-eint.c:626:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
626 | dsb(sy);
| ^
drivers/pinctrl/mediatek/mtk-eint.c:626:6: error: use of undeclared identifier 'sy'
626 | dsb(sy);
| ^
>> drivers/pinctrl/mediatek/mtk-eint.c:704:14: warning: no previous prototype for function 'mtk_eint_get_debounce_en' [-Wmissing-prototypes]
704 | unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
| ^
drivers/pinctrl/mediatek/mtk-eint.c:704:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
704 | unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
| ^
| static
>> drivers/pinctrl/mediatek/mtk-eint.c:727:14: warning: no previous prototype for function 'mtk_eint_get_debounce_value' [-Wmissing-prototypes]
727 | unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
| ^
drivers/pinctrl/mediatek/mtk-eint.c:727:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
727 | unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
| ^
| static
3 warnings and 4 errors generated.
vim +/dsb +605 drivers/pinctrl/mediatek/mtk-eint.c
589
590 int mtk_eint_do_suspend(struct mtk_eint *eint)
591 {
592 unsigned int i, j, port;
593
594 for (i = 0; i < eint->instance_number; i++) {
595 struct mtk_eint_instance inst = eint->instances[i];
596
597 for (j = 0; j < inst.number; j += 32) {
598 port = j >> 5;
599 writel_relaxed(~inst.wake_mask[port],
600 inst.base + port * 4 + eint->comp->regs->mask_set);
601 writel_relaxed(inst.wake_mask[port],
602 inst.base + port * 4 + eint->comp->regs->mask_clr);
603 }
604 }
> 605 dsb(sy);
606
607 return 0;
608 }
609 EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
610
611 int mtk_eint_do_resume(struct mtk_eint *eint)
612 {
613 unsigned int i, j, port;
614
615 for (i = 0; i < eint->instance_number; i++) {
616 struct mtk_eint_instance inst = eint->instances[i];
617
618 for (j = 0; j < inst.number; j += 32) {
619 port = j >> 5;
620 writel_relaxed(~inst.cur_mask[port],
621 inst.base + port * 4 + eint->comp->regs->mask_set);
622 writel_relaxed(inst.cur_mask[port],
623 inst.base + port * 4 + eint->comp->regs->mask_clr);
624 }
625 }
626 dsb(sy);
627
628 return 0;
629 }
630 EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
631
632 int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
633 unsigned int debounce)
634 {
635 int virq, eint_offset;
636 unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
637 dbnc;
638 static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
639 20000, 40000, 80000, 160000, 320000, 640000 };
640 struct irq_data *d;
641 unsigned int instance, index;
642 void __iomem *reg;
643
644 /*
645 * Due to different number of bit field, we only decode
646 * the coordinate here, instead of get the VA.
647 */
648 reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
649 &instance, &index);
650
651 if (!reg) {
652 dev_err(eint->dev, "%s invalid eint_num %lu\n",
653 __func__, eint_num);
654 return 0;
655 }
656
657 virq = irq_find_mapping(eint->domain, eint_num);
658 eint_offset = (index % 4) * 8;
659 d = irq_get_irq_data(virq);
660
661 reg = eint->instances[instance].base;
662 set_offset = (index / 4) * 4 + eint->comp->regs->dbnc_set;
663 clr_offset = (index / 4) * 4 + eint->comp->regs->dbnc_clr;
664
665 if (!mtk_eint_can_en_debounce(eint, eint_num))
666 return -EINVAL;
667
668 /*
669 * Check eint number to avoid access out-of-range
670 */
671 dbnc = ARRAY_SIZE(debounce_time) - 1;
672 for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
673 if (debounce <= debounce_time[i]) {
674 dbnc = i;
675 break;
676 }
677 }
678
679 if (!mtk_eint_get_mask(eint, eint_num)) {
680 mtk_eint_mask(d);
681 unmask = 1;
682 } else {
683 unmask = 0;
684 }
685
686 clr_bit = 0xff << eint_offset;
687 writel(clr_bit, reg + clr_offset);
688
689 bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS)
690 | MTK_EINT_DBNC_SET_EN) << eint_offset;
691 rst = MTK_EINT_DBNC_RST_BIT << eint_offset;
692 writel(rst | bit, reg + set_offset);
693
694 /* Delay should be (8T @ 32k) from dbc rst to work correctly. */
695 udelay(250);
696
697 if (unmask == 1)
698 mtk_eint_unmask(d);
699
700 return 0;
701 }
702 EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
703
> 704 unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
705 unsigned int eint_num)
706 {
707 unsigned int instance, index, bit;
708 void __iomem *reg;
709
710 reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
711 &instance, &index);
712
713 if (!reg) {
714 dev_err(eint->dev, "%s invalid eint_num %d\n",
715 __func__, eint_num);
716 return 0;
717 }
718
719 reg = eint->instances[instance].base +
720 (index / 4) * 4 + eint->comp->regs->dbnc_ctrl;
721
722 bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
723
724 return (readl(reg) & bit) ? 1 : 0;
725 }
726
> 727 unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
728 unsigned int eint_num)
729 {
730 unsigned int instance, index, mask, offset;
731 void __iomem *reg;
732
733 reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
734 &instance, &index);
735
736 if (!reg) {
737 dev_err(eint->dev, "%s invalid eint_num %d\n",
738 __func__, eint_num);
739 return 0;
740 }
741
742 reg = eint->instances[instance].base +
743 (index / 4) * 4 + eint->comp->regs->dbnc_ctrl;
744
745 offset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % 4) * 8);
746 mask = 0xf << offset;
747
748 return ((readl(reg) & mask) >> offset);
749 }
750
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
2024-12-02 8:50 chang hao
2024-12-02 11:50 ` kernel test robot
@ 2024-12-02 12:41 ` kernel test robot
1 sibling, 0 replies; 13+ messages in thread
From: kernel test robot @ 2024-12-02 12:41 UTC (permalink / raw)
To: chang hao, matthias.bgg, angelogioacchino.delregno, sean.wang,
linus.walleij
Cc: oe-kbuild-all, linux-mediatek, linux-gpio, linux-kernel,
linux-arm-kernel, Chhao Chang
Hi chang,
kernel test robot noticed the following build errors:
[auto build test ERROR on linusw-pinctrl/devel]
[also build test ERROR on linusw-pinctrl/for-next linus/master v6.13-rc1 next-20241128]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/chang-hao/pinctrl-mediatek-add-eint-new-design-for-mt8196/20241202-165544
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel
patch link: https://lore.kernel.org/r/20241202085024.25375-1-ot_chhao.chang%40mediatek.com
patch subject: [PATCH] pinctrl: mediatek: add eint new design for mt8196
config: arc-randconfig-001-20241202 (https://download.01.org/0day-ci/archive/20241202/202412022033.G153neOU-lkp@intel.com/config)
compiler: arc-elf-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241202/202412022033.G153neOU-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202412022033.G153neOU-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
>> drivers/pinctrl/mediatek/mtk-eint.c:246:6: warning: no previous prototype for 'mt6983_eint_ack' [-Wmissing-prototypes]
246 | void mt6983_eint_ack(struct irq_data *d)
| ^~~~~~~~~~~~~~~
drivers/pinctrl/mediatek/mtk-eint.c: In function 'mtk_eint_do_suspend':
>> drivers/pinctrl/mediatek/mtk-eint.c:605:9: error: implicit declaration of function 'dsb' [-Werror=implicit-function-declaration]
605 | dsb(sy);
| ^~~
>> drivers/pinctrl/mediatek/mtk-eint.c:605:13: error: 'sy' undeclared (first use in this function); did you mean 's8'?
605 | dsb(sy);
| ^~
| s8
drivers/pinctrl/mediatek/mtk-eint.c:605:13: note: each undeclared identifier is reported only once for each function it appears in
drivers/pinctrl/mediatek/mtk-eint.c: In function 'mtk_eint_do_resume':
drivers/pinctrl/mediatek/mtk-eint.c:626:13: error: 'sy' undeclared (first use in this function); did you mean 's8'?
626 | dsb(sy);
| ^~
| s8
drivers/pinctrl/mediatek/mtk-eint.c: At top level:
>> drivers/pinctrl/mediatek/mtk-eint.c:704:14: warning: no previous prototype for 'mtk_eint_get_debounce_en' [-Wmissing-prototypes]
704 | unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
| ^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/pinctrl/mediatek/mtk-eint.c:727:14: warning: no previous prototype for 'mtk_eint_get_debounce_value' [-Wmissing-prototypes]
727 | unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/dsb +605 drivers/pinctrl/mediatek/mtk-eint.c
589
590 int mtk_eint_do_suspend(struct mtk_eint *eint)
591 {
592 unsigned int i, j, port;
593
594 for (i = 0; i < eint->instance_number; i++) {
595 struct mtk_eint_instance inst = eint->instances[i];
596
597 for (j = 0; j < inst.number; j += 32) {
598 port = j >> 5;
599 writel_relaxed(~inst.wake_mask[port],
600 inst.base + port * 4 + eint->comp->regs->mask_set);
601 writel_relaxed(inst.wake_mask[port],
602 inst.base + port * 4 + eint->comp->regs->mask_clr);
603 }
604 }
> 605 dsb(sy);
606
607 return 0;
608 }
609 EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
610
611 int mtk_eint_do_resume(struct mtk_eint *eint)
612 {
613 unsigned int i, j, port;
614
615 for (i = 0; i < eint->instance_number; i++) {
616 struct mtk_eint_instance inst = eint->instances[i];
617
618 for (j = 0; j < inst.number; j += 32) {
619 port = j >> 5;
620 writel_relaxed(~inst.cur_mask[port],
621 inst.base + port * 4 + eint->comp->regs->mask_set);
622 writel_relaxed(inst.cur_mask[port],
623 inst.base + port * 4 + eint->comp->regs->mask_clr);
624 }
625 }
626 dsb(sy);
627
628 return 0;
629 }
630 EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
631
632 int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
633 unsigned int debounce)
634 {
635 int virq, eint_offset;
636 unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
637 dbnc;
638 static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
639 20000, 40000, 80000, 160000, 320000, 640000 };
640 struct irq_data *d;
641 unsigned int instance, index;
642 void __iomem *reg;
643
644 /*
645 * Due to different number of bit field, we only decode
646 * the coordinate here, instead of get the VA.
647 */
648 reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
649 &instance, &index);
650
651 if (!reg) {
652 dev_err(eint->dev, "%s invalid eint_num %lu\n",
653 __func__, eint_num);
654 return 0;
655 }
656
657 virq = irq_find_mapping(eint->domain, eint_num);
658 eint_offset = (index % 4) * 8;
659 d = irq_get_irq_data(virq);
660
661 reg = eint->instances[instance].base;
662 set_offset = (index / 4) * 4 + eint->comp->regs->dbnc_set;
663 clr_offset = (index / 4) * 4 + eint->comp->regs->dbnc_clr;
664
665 if (!mtk_eint_can_en_debounce(eint, eint_num))
666 return -EINVAL;
667
668 /*
669 * Check eint number to avoid access out-of-range
670 */
671 dbnc = ARRAY_SIZE(debounce_time) - 1;
672 for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
673 if (debounce <= debounce_time[i]) {
674 dbnc = i;
675 break;
676 }
677 }
678
679 if (!mtk_eint_get_mask(eint, eint_num)) {
680 mtk_eint_mask(d);
681 unmask = 1;
682 } else {
683 unmask = 0;
684 }
685
686 clr_bit = 0xff << eint_offset;
687 writel(clr_bit, reg + clr_offset);
688
689 bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS)
690 | MTK_EINT_DBNC_SET_EN) << eint_offset;
691 rst = MTK_EINT_DBNC_RST_BIT << eint_offset;
692 writel(rst | bit, reg + set_offset);
693
694 /* Delay should be (8T @ 32k) from dbc rst to work correctly. */
695 udelay(250);
696
697 if (unmask == 1)
698 mtk_eint_unmask(d);
699
700 return 0;
701 }
702 EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
703
> 704 unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
705 unsigned int eint_num)
706 {
707 unsigned int instance, index, bit;
708 void __iomem *reg;
709
710 reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
711 &instance, &index);
712
713 if (!reg) {
714 dev_err(eint->dev, "%s invalid eint_num %d\n",
715 __func__, eint_num);
716 return 0;
717 }
718
719 reg = eint->instances[instance].base +
720 (index / 4) * 4 + eint->comp->regs->dbnc_ctrl;
721
722 bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
723
724 return (readl(reg) & bit) ? 1 : 0;
725 }
726
> 727 unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
728 unsigned int eint_num)
729 {
730 unsigned int instance, index, mask, offset;
731 void __iomem *reg;
732
733 reg = mtk_eint_get_offset(eint, eint_num, MTK_EINT_NO_OFFSET,
734 &instance, &index);
735
736 if (!reg) {
737 dev_err(eint->dev, "%s invalid eint_num %d\n",
738 __func__, eint_num);
739 return 0;
740 }
741
742 reg = eint->instances[instance].base +
743 (index / 4) * 4 + eint->comp->regs->dbnc_ctrl;
744
745 offset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % 4) * 8);
746 mask = 0xf << offset;
747
748 return ((readl(reg) & mask) >> offset);
749 }
750
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH] pinctrl: mediatek: add eint new design for mt8196
@ 2024-10-25 2:43 chang hao
0 siblings, 0 replies; 13+ messages in thread
From: chang hao @ 2024-10-25 2:43 UTC (permalink / raw)
To: matthias.bgg, angelogioacchino.delregno, sean.wang, linus.walleij
Cc: linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel,
Chhao Chang
From: Chhao Chang <ot_chhao.chang@mediatek.com>
eint is divided from the original base address into base addresses
in five directions: east, south, west, north, and center.
Stores a limited number of eint numbers in each direction.
Signed-off-by: Chhao Chang <ot_chhao.chang@mediatek.com>
---
drivers/pinctrl/mediatek/mtk-eint.c | 830 +++++++++++++-----
drivers/pinctrl/mediatek/mtk-eint.h | 75 +-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 50 +-
3 files changed, 722 insertions(+), 233 deletions(-)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 27f0a54e12bf..afa53c7fce7f 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -17,16 +17,13 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of_irq.h>
+#include <linux/of_address.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_MAX 16
-#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
-#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
+static struct mtk_eint *global_eintc;
+struct mtk_eint_pin pin;
static const struct mtk_eint_regs mtk_generic_eint_regs = {
.stat = 0x000,
@@ -47,6 +44,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
+ .event = 0x800,
+ .event_set = 0x840,
+ .event_clr = 0x880,
+ .raw_stat = 0xa00,
};
const unsigned int debounce_time_mt2701[] = {
@@ -64,60 +65,145 @@ const unsigned int debounce_time_mt6795[] = {
};
EXPORT_SYMBOL_GPL(debounce_time_mt6795);
-static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
+/*
+ * Return the iomem of specific register ofset and decode the coordinate
+ * (instance, index) from global eint number.
+ * If return NULL, then it must be either out-of-range or do-not-support.
+ */
+static void __iomem *mtk_eint_get_ofset(struct mtk_eint *eint,
unsigned int eint_num,
- unsigned int offset)
+ unsigned int ofset,
+ unsigned int *instance,
+ unsigned int *index)
{
- unsigned int eint_base = 0;
void __iomem *reg;
- if (eint_num >= eint->hw->ap_num)
- eint_base = eint->hw->ap_num;
+ if (eint_num >= eint->total_pin_number ||
+ !eint->pins[eint_num].enabled) {
+ WARN_ON(1);
+ return NULL;
+ }
- reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+ *instance = eint->pins[eint_num].instance;
+ *index = eint->pins[eint_num].index;
+ reg = eint->instances[*instance].base + ofset + (*index / MAX_BIT * REG_OFSET);
return reg;
}
+/*
+ * Generate helper function to access property register of a dedicate pin.
+ */
+#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFSET) \
+static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
+ unsigned int eint_num) \
+{ \
+ unsigned int instance, index; \
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num, \
+ _OFSET, \
+ &instance, &index); \
+ unsigned int bit = BIT(index & 0x1f);\
+\
+ if (!reg) { \
+ dev_err(eint->dev, "%s invalid eint_num %d\n", \
+ __func__, eint_num); \
+ return 0;\
+ } \
+\
+ return !!(readl(reg) & bit); \
+}
+
+DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
+DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
+DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
+DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
+DEFINE_EINT_GET_FUNCTION(dom_en, eint->comp->regs->dom_en);
+DEFINE_EINT_GET_FUNCTION(event, eint->comp->regs->event);
+DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
+
+int dump_eint_pin_status(unsigned int eint_num)
+{
+ unsigned int stat, raw_stat, mask, sens, pol, dom_en, event;
+
+ if (eint_num < 0 || eint_num > global_eintc->total_pin_number)
+ return ENODEV;
+
+ stat = mtk_eint_get_stat(global_eintc, eint_num);
+ raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
+ mask = mtk_eint_get_mask(global_eintc, eint_num);
+ sens = mtk_eint_get_sens(global_eintc, eint_num);
+ pol = mtk_eint_get_pol(global_eintc, eint_num);
+ dom_en = mtk_eint_get_dom_en(global_eintc, eint_num);
+ event = mtk_eint_get_event(global_eintc, eint_num);
+ dev_info(global_eintc->dev, "%s eint_num:%u=stat:%u,raw:%u, \
+ mask:%u, sens:%u,pol:%u,dom_en:%u,event:%u\n",
+ __func__, eint_num, stat, raw_stat, mask, sens,
+ pol, dom_en, event);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dump_eint_pin_status);
+
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->sens,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
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)
+ if (eint->pins[eint_num].debounce &&
+ sens != MTK_EINT_EDGE_SENSITIVE)
return 1;
else
return 0;
}
-static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)
{
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);
+ unsigned int reg_ofset;
+ unsigned int instance, index, mask, port;
+ void __iomem *reg;
- curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ mask = BIT(index & 0x1f);
+ port = index >> REG_GROUP;
+ reg = eint->instances[instance].base + port * REG_OFSET;
+
+ curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, eint_num);
do {
start_level = curr_level;
if (start_level)
- reg_offset = eint->regs->pol_clr;
+ reg_ofset = eint->comp->regs->pol_clr;
else
- reg_offset = eint->regs->pol_set;
- writel(mask, reg + reg_offset);
+ reg_ofset = eint->comp->regs->pol_set;
+
+ writel(mask, reg + reg_ofset);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
- hwirq);
+ eint_num);
} while (start_level != curr_level);
return start_level;
@@ -126,11 +212,19 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_set,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] &= ~mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] &= ~mask;
writel(mask, reg);
}
@@ -138,43 +232,91 @@ static void mtk_eint_mask(struct irq_data *d)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_clr,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] |= mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] |= mask;
writel(mask, reg);
- if (eint->dual_edge[d->hwirq])
+ if (eint->pins[d->hwirq].dual_edge)
mtk_eint_flip_edge(eint, d->hwirq);
}
-static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
+static void mtk_eint_ack(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ unsigned int instance, index;
+ void __iomem *reg;
+ unsigned int bit;
+
+ if (eint->comp->ops.ack)
+ eint->comp->ops.ack(d);
+ else {
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->ack,
+ &instance, &index);
+ bit = BIT(index & 0x1f);
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
+
+ writel(bit, reg);
+ }
+}
+
+static void mtk_eint_soft_set(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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_set,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- return !!(readl(reg) & bit);
+ writel(bit, reg);
}
-static void mtk_eint_ack(struct irq_data *d)
+static void mtk_eint_soft_clr(struct mtk_eint *eint,
+ unsigned int eint_num)
{
- 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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_clr,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- writel(mask, reg);
+ writel(bit, 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);
- bool masked;
- u32 mask = BIT(d->hwirq & 0x1f);
+ u32 mask;
+ unsigned int instance, index;
void __iomem *reg;
if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
@@ -186,36 +328,42 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
}
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- eint->dual_edge[d->hwirq] = 1;
+ eint->pins[d->hwirq].dual_edge = 1;
else
- eint->dual_edge[d->hwirq] = 0;
+ eint->pins[d->hwirq].dual_edge = 0;
- if (!mtk_eint_get_mask(eint, d->hwirq)) {
- mtk_eint_mask(d);
- masked = false;
- } else {
- masked = true;
- }
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_set,
+ &instance, &index);
- 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);
- }
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_set,
+ &instance, &index);
- 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 (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
}
- mtk_eint_ack(d);
- if (!masked)
- mtk_eint_unmask(d);
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (eint->pins[d->hwirq].dual_edge)
+ mtk_eint_flip_edge(eint, d->hwirq);
return 0;
}
@@ -223,30 +371,28 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
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;
+ unsigned int instance, index, shift, port;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
+ }
+
+ shift = index & 0x1f;
+ port = index >> REG_GROUP;
if (on)
- eint->wake_mask[reg] |= BIT(shift);
+ eint->instances[instance].wake_mask[port] |= BIT(shift);
else
- eint->wake_mask[reg] &= ~BIT(shift);
+ eint->instances[instance].wake_mask[port] &= ~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 int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -290,7 +436,7 @@ static void mtk_eint_irq_release_resources(struct irq_data *d)
}
static struct irq_chip mtk_eint_irq_chip = {
- .name = "mt-eint",
+ .name = "mtk-eint",
.irq_disable = mtk_eint_mask,
.irq_mask = mtk_eint_mask,
.irq_unmask = mtk_eint_unmask,
@@ -301,35 +447,51 @@ static struct irq_chip mtk_eint_irq_chip = {
.irq_release_resources = mtk_eint_irq_release_resources,
};
+/*
+ * Configure all EINT pins as domain 0, which only belongs to AP.
+ */
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
- void __iomem *dom_en = eint->base + eint->regs->dom_en;
- void __iomem *mask_set = eint->base + eint->regs->mask_set;
- unsigned int i;
-
- for (i = 0; i < eint->hw->ap_num; i += 32) {
- writel(0xffffffff, dom_en);
- writel(0xffffffff, mask_set);
- dom_en += 4;
- mask_set += 4;
+ void __iomem *reg,*eevt_clr;
+ unsigned int i, j;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ reg = eint->instances[i].base + eint->comp->regs->dom_en;
+ eevt_clr = eint->instances[i].base + eint->comp->regs->event_clr;
+ for (j = 0; j < eint->instances[i].number; j += MAX_BIT, reg += REG_OFSET, eevt_clr += REG_OFSET) {
+ writel(REG_VAL, reg);
+ writel(REG_VAL, eevt_clr);
+ }
}
return 0;
}
static inline void
-mtk_eint_debounce_process(struct mtk_eint *eint, int index)
+mtk_eint_debounce_process(struct mtk_eint *eint, int eint_num)
{
- unsigned int rst, ctrl_offset;
+ unsigned int rst, ctrl_ofset;
unsigned int bit, dbnc;
+ unsigned int instance, index;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
+
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+ dbnc = readl(eint->instances[instance].base + ctrl_ofset);
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
- 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);
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ rst = MTK_EINT_DBNC_RST_BIT << ((index % REG_OFSET) * DB_GROUP);
+ writel(rst, eint->instances[instance].base + ctrl_ofset);
}
}
@@ -337,65 +499,72 @@ 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, mask_offset, index;
- void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
- int dual_edge, start_level, curr_level;
+ unsigned int status, i, j;
+ int shift, port, eint_num, virq;
+ unsigned int dual_edge, start_level, curr_level;
+ struct mtk_eint_instance eint_instance;
+ void __iomem *addr;
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);
- mask_offset = eint_num >> 5;
- index = eint_num + offset;
- status &= ~BIT(offset);
-
- /*
- * If we get an interrupt on pin that was only required
- * for wake (but no real interrupt requested), mask the
- * interrupt (as would mtk_eint_resume do anyway later
- * in the resume sequence).
- */
- if (eint->wake_mask[mask_offset] & BIT(offset) &&
- !(eint->cur_mask[mask_offset] & BIT(offset))) {
- writel_relaxed(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->mask_set);
- }
-
- 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);
- }
+ for (i = 0; i < eint->instance_number; i++) {
+ eint_instance = eint->instances[i];
- generic_handle_domain_irq(eint->domain, index);
+ /* Iterate all pins by port */
+ for (j = 0; j < eint_instance.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ status = readl(eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->stat);
+ while (status) {
+ shift = __ffs(status);
+ status &= ~BIT(shift);
- if (dual_edge) {
- curr_level = mtk_eint_flip_edge(eint, index);
+ eint_num = eint->instances[i].pin_list[shift + j];
+ virq = irq_find_mapping(eint->domain, eint_num);
/*
- * If level changed, we might lost one edge
- * interrupt, raised it through soft-irq.
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
*/
- if (start_level != curr_level)
- writel(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->soft_set);
- }
+ if (eint->instances[i].wake_mask[port] & BIT(shift) &&
+ !(eint->instances[i].cur_mask[port] & BIT(shift))) {
+ addr = eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->mask_set;
+ writel_relaxed(BIT(shift), addr);
+ }
+
+ dual_edge = eint->pins[eint_num].dual_edge;
+ if (dual_edge) {
+ /*
+ * Clear soft-irq in case we raised it last
+ * time.
+ */
+ mtk_eint_soft_clr(eint, eint_num);
+
+ start_level =
+ eint->gpio_xlate->get_gpio_state(eint->pctl,
+ eint_num);
+ }
+
+ generic_handle_irq(virq);
+
+ if (dual_edge) {
+ curr_level = mtk_eint_flip_edge(eint, eint_num);
+
+ /*
+ * If level changed, we might lost one edge
+ * interrupt, raised it through soft-irq.
+ */
+ if (start_level != curr_level)
+ mtk_eint_soft_set(eint, eint_num);
+ }
+
+ if (eint->pins[eint_num].debounce)
+ mtk_eint_debounce_process(eint, eint_num);
- if (index < eint->hw->db_cnt)
- mtk_eint_debounce_process(eint, index);
+ }
}
}
chained_irq_exit(chip, desc);
@@ -403,7 +572,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -411,7 +593,20 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
int mtk_eint_do_resume(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -420,27 +615,45 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
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,
+ int virq, eint_ofset;
+ unsigned int set_ofset, bit, clr_bit, clr_ofset, rst, i, unmask,
dbnc;
+ static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
+ 20000, 40000, 80000, 160000, 320000, 640000 };
struct irq_data *d;
+ unsigned int instance, index;
+ void __iomem *reg;
- if (!eint->hw->db_time)
- return -EOPNOTSUPP;
+ /*
+ * Due to different number of bit field, we only decode
+ * the coordinate here, instead of get the VA.
+ */
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, eint_num);
+ return 0;
+ }
virq = irq_find_mapping(eint->domain, eint_num);
- eint_offset = (eint_num % 4) * 8;
+ eint_ofset = (index % REG_OFSET) * DB_GROUP;
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;
+ reg = eint->instances[instance].base;
+ set_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ clr_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
- dbnc = eint->num_db_time;
- for (i = 0; i < eint->num_db_time; i++) {
- if (debounce <= eint->hw->db_time[i]) {
+ /*
+ * Check eint number to avoid access out-of-range
+ */
+ dbnc = ARRAY_SIZE(debounce_time) - 1;
+ for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+ if (debounce <= debounce_time[i]) {
dbnc = i;
break;
}
@@ -449,23 +662,20 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
if (!mtk_eint_get_mask(eint, eint_num)) {
mtk_eint_mask(d);
unmask = 1;
- } else {
+ } else
unmask = 0;
- }
- clr_bit = 0xff << eint_offset;
- writel(clr_bit, eint->base + clr_offset);
+ clr_bit = 0xff << eint_ofset;
+ writel(clr_bit, reg + clr_ofset);
- 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);
+ bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS)
+ | MTK_EINT_DBNC_SET_EN) << eint_ofset;
+ rst = MTK_EINT_DBNC_RST_BIT << eint_ofset;
+ writel(rst | bit, reg + set_ofset);
/*
- * Delay a while (more than 2T) to wait for hw debounce counter reset
- * work correctly.
+ * Delay should be (8T @ 32k) from dbc rst to work correctly.
*/
- udelay(1);
if (unmask == 1)
mtk_eint_unmask(d);
@@ -473,6 +683,53 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
}
EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
+unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, bit;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
+
+ return (readl(reg) & bit) ? 1 : 0;
+}
+
+unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, mask, ofset;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ ofset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % REG_OFSET) * DB_GROUP);
+ mask = 0xf << ofset;
+
+ return ((readl(reg) & mask) >> ofset);
+}
+
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
int irq;
@@ -485,45 +742,208 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
}
EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
+static const struct mtk_eint_compatible default_compat = {
+ .regs = &mtk_generic_eint_regs,
+};
+
+static const struct of_device_id eint_compatible_ids[] = {
+ { }
+};
+
int mtk_eint_do_init(struct mtk_eint *eint)
{
- int i;
+ int i, virq;
+ unsigned int size;
+ eint->instance_number = 1;
+
+ for (i = 0; i < eint->total_pin_number; i++) {
+ eint->pins[i].enabled = true;
+ eint->pins[i].instance = 0;
+ eint->pins[i].index = i;
+ eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
+
+ eint->instances[i].pin_list[i] = i;
+ eint->instances[i].number++;
+ }
- /* If clients don't assign a specific regs, let's use generic one */
- if (!eint->regs)
- eint->regs = &mtk_generic_eint_regs;
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
- eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->wake_mask), GFP_KERNEL);
- if (!eint->wake_mask)
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
+ eint->domain = irq_domain_add_linear(eint->dev->of_node,
+ eint->total_pin_number,
+ &irq_domain_simple_ops, NULL);
+ if (!eint->domain)
return -ENOMEM;
- eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->cur_mask), GFP_KERNEL);
- if (!eint->cur_mask)
+ mtk_eint_hw_init(eint);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ 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);
+
+ global_eintc = eint;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+
+int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ int i, virq, matrix_number = 0;
+ struct device_node *node;
+ unsigned int ret, size, ofset;
+ unsigned int id, inst, idx, support_deb;
+
+ const phandle *ph;
+
+ ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
+ if (!ph) {
+ dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
+ return -ENODEV;
+ }
+
+ node = of_find_node_by_phandle(be32_to_cpup(ph));
+ if (!node) {
+ dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(node, "mediatek,total-pin-number",
+ &eint->total_pin_number);
+ if (ret) {
+ dev_err(eint->dev,
+ "%s cannot read total-pin-number from device node.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
+ eint->total_pin_number);
+
+ ret = of_property_read_u32(node, "mediatek,instance-num",
+ &eint->instance_number);
+ if (ret)
+ eint->instance_number = 1; // only 1 instance in legacy chip
+
+ size = eint->instance_number * sizeof(struct mtk_eint_instance);
+ eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->instances)
return -ENOMEM;
- eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
- sizeof(int), GFP_KERNEL);
- if (!eint->dual_edge)
+ size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
+ eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->pins)
return -ENOMEM;
+ for (i = 0; i < eint->instance_number; i++) {
+ ret = of_property_read_string_index(node, "reg-name", i,
+ &(eint->instances[i].name));
+ if (ret) {
+ dev_info(eint->dev,
+ "%s cannot read the name of instance %d.\n",
+ __func__, i);
+ }
+
+ eint->instances[i].base = of_iomap(node, i);
+ if (!eint->instances[i].base)
+ return -ENOMEM;
+ }
+
+ matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
+ if (matrix_number < 0) {
+ matrix_number = eint->total_pin_number;
+ dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+ } else
+ dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+
+ for (i = 0; i < matrix_number; i++) {
+ ofset = i * REG_OFSET;
+
+ ret = of_property_read_u32_index(node, "mediatek,pins",
+ ofset, &id);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+FIRST, &inst);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+SECOND, &idx);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+THIRD, &support_deb);
+
+ /* Legacy chip which no need to give coordinate list */
+ if (ret) {
+ id = i;
+ inst = 0;
+ idx = i;
+ support_deb = (i < MAX_BIT) ? 1 : 0;
+ }
+
+ eint->pins[id].enabled = true;
+ eint->pins[id].instance = inst;
+ eint->pins[id].index = idx;
+ eint->pins[id].debounce = support_deb;
+
+ eint->instances[inst].pin_list[idx] = id;
+ eint->instances[inst].number++;
+
+#if defined(MTK_EINT_DEBUG)
+ pin = eint->pins[id];
+ dev_info(eint->dev,
+ "EINT%u in (%u-%u), su_deb = %u",
+ id,
+ pin.instance,
+ eint->instances[inst].number,
+ pin.debounce,
+#endif
+ }
+
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
+ eint->irq = irq_of_parse_and_map(node, 0);
+ if (!eint->irq) {
+ dev_err(eint->dev,
+ "%s IRQ parse fail.\n", __func__);
+ return -EINVAL;
+ }
+
eint->domain = irq_domain_add_linear(eint->dev->of_node,
- eint->hw->ap_num,
+ eint->total_pin_number,
&irq_domain_simple_ops, NULL);
if (!eint->domain)
return -ENOMEM;
- if (eint->hw->db_time) {
- for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
- if (eint->hw->db_time[i] == 0)
- break;
- eint->num_db_time = i;
- }
-
mtk_eint_hw_init(eint);
- for (i = 0; i < eint->hw->ap_num; i++) {
- int virq = irq_create_mapping(eint->domain, i);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ virq = irq_create_mapping(eint->domain, i);
irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
handle_level_irq);
@@ -533,9 +953,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)
irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
eint);
+ global_eintc = eint;
+
return 0;
}
-EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+EXPORT_SYMBOL_GPL(mtk_eint_do_init_v2);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MediaTek EINT Driver");
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 6139b16cd225..aa17a6073029 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -11,6 +11,25 @@
#include <linux/irqdomain.h>
+#define MAX_PIN 999
+#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)
+#define MTK_EINT_NO_OFSET 0
+#define MAX_BIT 32
+#define REG_OFSET 4
+#define REG_GROUP 5
+#define REG_VAL 0xFFFFFFFF
+#define DB_GROUP 8
+#define FIRST 1
+#define SECOND 2
+#define THIRD 3
+#define ARRAY_0 4
+
+//#define MTK_EINT_DEBUG
+
struct mtk_eint_regs {
unsigned int stat;
unsigned int ack;
@@ -30,6 +49,36 @@ struct mtk_eint_regs {
unsigned int dbnc_ctrl;
unsigned int dbnc_set;
unsigned int dbnc_clr;
+ unsigned int event;
+ unsigned int event_set;
+ unsigned int event_clr;
+ unsigned int raw_stat;
+};
+
+struct mtk_eint_ops {
+ void (*ack)(struct irq_data *d);
+};
+
+struct mtk_eint_compatible {
+ struct mtk_eint_ops ops;
+ const struct mtk_eint_regs *regs;
+};
+
+struct mtk_eint_instance {
+ const char *name;
+ void __iomem *base;
+ unsigned int number;
+ unsigned int pin_list[MAX_PIN];
+ unsigned int *wake_mask;
+ unsigned int *cur_mask;
+};
+
+struct mtk_eint_pin {
+ bool enabled;
+ unsigned int instance;
+ unsigned int index;
+ bool debounce;
+ bool dual_edge;
};
struct mtk_eint_hw {
@@ -60,11 +109,14 @@ struct mtk_eint {
struct irq_domain *domain;
int irq;
- int *dual_edge;
- u32 *wake_mask;
- u32 *cur_mask;
-
- /* Used to fit into various EINT device */
+ /* An array to record the coordinate, index by global EINT ID */
+ struct mtk_eint_pin *pins;
+ /* An array to record the global EINT ID, index by coordinate*/
+ struct mtk_eint_instance *instances;
+ unsigned int total_pin_number;
+ unsigned int instance_number;
+ unsigned int dump_target_eint;
+ const struct mtk_eint_compatible *comp;
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
u16 num_db_time;
@@ -74,13 +126,15 @@ struct mtk_eint {
const struct mtk_eint_xt *gpio_xlate;
};
-#if IS_ENABLED(CONFIG_EINT_MTK)
+#if (IS_ENABLED(CONFIG_EINT_MTK) || IS_ENABLED(CONFIG_DEVICE_MODULES_EINT_MTK))
int mtk_eint_do_init(struct mtk_eint *eint);
+int mtk_eint_do_init_v2(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);
+int dump_eint_pin_status(unsigned int eint_num);
#else
static inline int mtk_eint_do_init(struct mtk_eint *eint)
@@ -88,6 +142,11 @@ static inline int mtk_eint_do_init(struct mtk_eint *eint)
return -EOPNOTSUPP;
}
+static inline int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
@@ -108,5 +167,9 @@ static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
return -EOPNOTSUPP;
}
+static inline int dump_eint_pin_status(unsigned int eint_num)
+{
+ return -EOPNOTSUPP;
+}
#endif
#endif /* __MTK_EINT_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index 54301fbba524..3740e868c650 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -375,33 +375,37 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
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;
-
- hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
- if (IS_ERR(hw->eint->base)) {
- ret = PTR_ERR(hw->eint->base);
- goto err_free_eint;
- }
+ if (hw->soc->eint_hw) {
+ hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
+ if (!hw->eint)
+ return -ENOMEM;
+
+ hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
+ if (IS_ERR(hw->eint->base)) {
+ ret = PTR_ERR(hw->eint->base);
+ goto err_free_eint;
+ }
- hw->eint->irq = irq_of_parse_and_map(np, 0);
- if (!hw->eint->irq) {
- ret = -EINVAL;
- goto err_free_eint;
- }
+ hw->eint->irq = irq_of_parse_and_map(np, 0);
+ if (!hw->eint->irq) {
+ ret = -EINVAL;
+ goto err_free_eint;
+ }
- if (!hw->soc->eint_hw) {
- ret = -ENODEV;
- goto err_free_eint;
- }
+ 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);
- hw->eint->dev = &pdev->dev;
- hw->eint->hw = hw->soc->eint_hw;
- hw->eint->pctl = hw;
- hw->eint->gpio_xlate = &mtk_eint_xt;
+ } else {
+ hw->eint->dev = &pdev->dev;
+ hw->eint->pctl = hw;
+ hw->eint->gpio_xlate = &mtk_eint_xt;
- return mtk_eint_do_init(hw->eint);
+ return mtk_eint_do_init_v2(hw->eint);
+ }
err_free_eint:
devm_kfree(hw->dev, hw->eint);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH] pinctrl: mediatek: add eint new design for mt8196
@ 2024-10-24 14:15 chang hao
2024-10-24 15:55 ` AngeloGioacchino Del Regno
0 siblings, 1 reply; 13+ messages in thread
From: chang hao @ 2024-10-24 14:15 UTC (permalink / raw)
To: matthias.bgg, angelogioacchino.delregno, sean.wang, linus.walleij
Cc: linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel,
Chhao Chang
From: Chhao Chang <ot_chhao.chang@mediatek.com>
eint is divided from the original base address into base addresses
in five directions: east, south, west, north, and center.
Stores a limited number of eint numbers in each direction.
Signed-off-by: Chhao Chang <ot_chhao.chang@mediatek.com>
---
drivers/pinctrl/mediatek/mtk-eint.c | 830 +++++++++++++-----
drivers/pinctrl/mediatek/mtk-eint.h | 75 +-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 50 +-
3 files changed, 722 insertions(+), 233 deletions(-)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 27f0a54e12bf..0bb017eb1893 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -17,16 +17,13 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of_irq.h>
+#include <linux/of_address.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_MAX 16
-#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
-#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
+static struct mtk_eint *global_eintc;
+struct mtk_eint_pin pin;
static const struct mtk_eint_regs mtk_generic_eint_regs = {
.stat = 0x000,
@@ -47,6 +44,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
+ .event = 0x800,
+ .event_set = 0x840,
+ .event_clr = 0x880,
+ .raw_stat = 0xa00,
};
const unsigned int debounce_time_mt2701[] = {
@@ -64,60 +65,145 @@ const unsigned int debounce_time_mt6795[] = {
};
EXPORT_SYMBOL_GPL(debounce_time_mt6795);
-static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
+/*
+ * Return the iomem of specific register ofset and decode the coordinate
+ * (instance, index) from global eint number.
+ * If return NULL, then it must be either out-of-range or do-not-support.
+ */
+static void __iomem *mtk_eint_get_ofset(struct mtk_eint *eint,
unsigned int eint_num,
- unsigned int offset)
+ unsigned int ofset,
+ unsigned int *instance,
+ unsigned int *index)
{
- unsigned int eint_base = 0;
void __iomem *reg;
- if (eint_num >= eint->hw->ap_num)
- eint_base = eint->hw->ap_num;
+ if (eint_num >= eint->total_pin_number ||
+ !eint->pins[eint_num].enabled) {
+ WARN_ON(1);
+ return NULL;
+ }
- reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+ *instance = eint->pins[eint_num].instance;
+ *index = eint->pins[eint_num].index;
+ reg = eint->instances[*instance].base + ofset + (*index / MAX_BIT * REG_OFSET);
return reg;
}
+/*
+ * Generate helper function to access property register of a dedicate pin.
+ */
+#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFSET) \
+static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
+ unsigned int eint_num) \
+{ \
+ unsigned int instance, index; \
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num, \
+ _OFSET, \
+ &instance, &index); \
+ unsigned int bit = BIT(index & 0x1f);\
+\
+ if (!reg) { \
+ dev_err(eint->dev, "%s invalid eint_num %d\n", \
+ __func__, eint_num); \
+ return 0;\
+ } \
+\
+ return !!(readl(reg) & bit); \
+}
+
+DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
+DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
+DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
+DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
+DEFINE_EINT_GET_FUNCTION(dom_en, eint->comp->regs->dom_en);
+DEFINE_EINT_GET_FUNCTION(event, eint->comp->regs->event);
+DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
+
+int dump_eint_pin_status(unsigned int eint_num)
+{
+ unsigned int stat, raw_stat, mask, sens, pol, dom_en, event;
+
+ if (eint_num < 0 || eint_num > global_eintc->total_pin_number)
+ return ENODEV;
+
+ stat = mtk_eint_get_stat(global_eintc, eint_num);
+ raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
+ mask = mtk_eint_get_mask(global_eintc, eint_num);
+ sens = mtk_eint_get_sens(global_eintc, eint_num);
+ pol = mtk_eint_get_pol(global_eintc, eint_num);
+ dom_en = mtk_eint_get_dom_en(global_eintc, eint_num);
+ event = mtk_eint_get_event(global_eintc, eint_num);
+ dev_info(global_eintc->dev, "%s eint_num:%u=stat:%u,raw:%u, \
+ mask:%u, sens:%u,pol:%u,dom_en:%u,event:%u\n",
+ __func__, eint_num, stat, raw_stat, mask, sens,
+ pol, dom_en, event);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dump_eint_pin_status);
+
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->sens,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
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)
+ if (eint->pins[eint_num].debounce &&
+ sens != MTK_EINT_EDGE_SENSITIVE)
return 1;
else
return 0;
}
-static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)
{
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);
+ unsigned int reg_ofset;
+ unsigned int instance, index, mask, port;
+ void __iomem *reg;
- curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ mask = BIT(index & 0x1f);
+ port = index >> REG_GROUP;
+ reg = eint->instances[instance].base + port * REG_OFSET;
+
+ curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, eint_num);
do {
start_level = curr_level;
if (start_level)
- reg_offset = eint->regs->pol_clr;
+ reg_ofset = eint->comp->regs->pol_clr;
else
- reg_offset = eint->regs->pol_set;
- writel(mask, reg + reg_offset);
+ reg_ofset = eint->comp->regs->pol_set;
+
+ writel(mask, reg + reg_ofset);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
- hwirq);
+ eint_num);
} while (start_level != curr_level);
return start_level;
@@ -126,11 +212,19 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_set,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] &= ~mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] &= ~mask;
writel(mask, reg);
}
@@ -138,43 +232,91 @@ static void mtk_eint_mask(struct irq_data *d)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_clr,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] |= mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] |= mask;
writel(mask, reg);
- if (eint->dual_edge[d->hwirq])
+ if (eint->pins[d->hwirq].dual_edge)
mtk_eint_flip_edge(eint, d->hwirq);
}
-static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
+static void mtk_eint_ack(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ unsigned int instance, index;
+ void __iomem *reg;
+ unsigned int bit;
+
+ if (eint->comp->ops.ack)
+ eint->comp->ops.ack(d);
+ else {
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->ack,
+ &instance, &index);
+ bit = BIT(index & 0x1f);
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
+
+ writel(bit, reg);
+ }
+}
+
+static void mtk_eint_soft_set(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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_set,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- return !!(readl(reg) & bit);
+ writel(bit, reg);
}
-static void mtk_eint_ack(struct irq_data *d)
+static void mtk_eint_soft_clr(struct mtk_eint *eint,
+ unsigned int eint_num)
{
- 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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_clr,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- writel(mask, reg);
+ writel(bit, 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);
- bool masked;
- u32 mask = BIT(d->hwirq & 0x1f);
+ u32 mask;
+ unsigned int instance, index;
void __iomem *reg;
if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
@@ -186,36 +328,42 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
}
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- eint->dual_edge[d->hwirq] = 1;
+ eint->pins[d->hwirq].dual_edge = 1;
else
- eint->dual_edge[d->hwirq] = 0;
+ eint->pins[d->hwirq].dual_edge = 0;
- if (!mtk_eint_get_mask(eint, d->hwirq)) {
- mtk_eint_mask(d);
- masked = false;
- } else {
- masked = true;
- }
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_set,
+ &instance, &index);
- 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);
- }
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_set,
+ &instance, &index);
- 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 (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
}
- mtk_eint_ack(d);
- if (!masked)
- mtk_eint_unmask(d);
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (eint->pins[d->hwirq].dual_edge)
+ mtk_eint_flip_edge(eint, d->hwirq);
return 0;
}
@@ -223,30 +371,28 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
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;
+ unsigned int instance, index, shift, port;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
+ }
+
+ shift = index & 0x1f;
+ port = index >> REG_GROUP;
if (on)
- eint->wake_mask[reg] |= BIT(shift);
+ eint->instances[instance].wake_mask[port] |= BIT(shift);
else
- eint->wake_mask[reg] &= ~BIT(shift);
+ eint->instances[instance].wake_mask[port] &= ~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 int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -290,7 +436,7 @@ static void mtk_eint_irq_release_resources(struct irq_data *d)
}
static struct irq_chip mtk_eint_irq_chip = {
- .name = "mt-eint",
+ .name = "mtk-eint",
.irq_disable = mtk_eint_mask,
.irq_mask = mtk_eint_mask,
.irq_unmask = mtk_eint_unmask,
@@ -301,35 +447,51 @@ static struct irq_chip mtk_eint_irq_chip = {
.irq_release_resources = mtk_eint_irq_release_resources,
};
+/*
+ * Configure all EINT pins as domain 0, which only belongs to AP.
+ */
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
- void __iomem *dom_en = eint->base + eint->regs->dom_en;
- void __iomem *mask_set = eint->base + eint->regs->mask_set;
- unsigned int i;
-
- for (i = 0; i < eint->hw->ap_num; i += 32) {
- writel(0xffffffff, dom_en);
- writel(0xffffffff, mask_set);
- dom_en += 4;
- mask_set += 4;
+ void __iomem *reg,*eevt_clr;
+ unsigned int i, j;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ reg = eint->instances[i].base + eint->comp->regs->dom_en;
+ eevt_clr = eint->instances[i].base + eint->comp->regs->event_clr;
+ for (j = 0; j < eint->instances[i].number; j += MAX_BIT, reg += REG_OFSET, eevt_clr += REG_OFSET) {
+ writel(REG_VAL, reg);
+ writel(REG_VAL, eevt_clr);
+ }
}
return 0;
}
static inline void
-mtk_eint_debounce_process(struct mtk_eint *eint, int index)
+mtk_eint_debounce_process(struct mtk_eint *eint, int eint_num)
{
- unsigned int rst, ctrl_offset;
+ unsigned int rst, ctrl_ofset;
unsigned int bit, dbnc;
+ unsigned int instance, index;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
+
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+ dbnc = readl(eint->instances[instance].base + ctrl_ofset);
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
- 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);
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ rst = MTK_EINT_DBNC_RST_BIT << ((index % REG_OFSET) * DB_GROUP);
+ writel(rst, eint->instances[instance].base + ctrl_ofset);
}
}
@@ -337,65 +499,72 @@ 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, mask_offset, index;
- void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
- int dual_edge, start_level, curr_level;
+ unsigned int status, i, j;
+ int shift, port, eint_num, virq;
+ unsigned int dual_edge, start_level, curr_level;
+ struct mtk_eint_instance eint_instance;
+ void __iomem *addr;
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);
- mask_offset = eint_num >> 5;
- index = eint_num + offset;
- status &= ~BIT(offset);
-
- /*
- * If we get an interrupt on pin that was only required
- * for wake (but no real interrupt requested), mask the
- * interrupt (as would mtk_eint_resume do anyway later
- * in the resume sequence).
- */
- if (eint->wake_mask[mask_offset] & BIT(offset) &&
- !(eint->cur_mask[mask_offset] & BIT(offset))) {
- writel_relaxed(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->mask_set);
- }
-
- 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);
- }
+ for (i = 0; i < eint->instance_number; i++) {
+ eint_instance = eint->instances[i];
- generic_handle_domain_irq(eint->domain, index);
+ /* Iterate all pins by port */
+ for (j = 0; j < eint_instance.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ status = readl(eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->stat);
+ while (status) {
+ shift = __ffs(status);
+ status &= ~BIT(shift);
- if (dual_edge) {
- curr_level = mtk_eint_flip_edge(eint, index);
+ eint_num = eint->instances[i].pin_list[shift + j];
+ virq = irq_find_mapping(eint->domain, eint_num);
/*
- * If level changed, we might lost one edge
- * interrupt, raised it through soft-irq.
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
*/
- if (start_level != curr_level)
- writel(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->soft_set);
- }
+ if (eint->instances[i].wake_mask[port] & BIT(shift) &&
+ !(eint->instances[i].cur_mask[port] & BIT(shift))) {
+ addr = eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->mask_set;
+ writel_relaxed(BIT(shift), addr);
+ }
+
+ dual_edge = eint->pins[eint_num].dual_edge;
+ if (dual_edge) {
+ /*
+ * Clear soft-irq in case we raised it last
+ * time.
+ */
+ mtk_eint_soft_clr(eint, eint_num);
+
+ start_level =
+ eint->gpio_xlate->get_gpio_state(eint->pctl,
+ eint_num);
+ }
+
+ generic_handle_irq(virq);
+
+ if (dual_edge) {
+ curr_level = mtk_eint_flip_edge(eint, eint_num);
+
+ /*
+ * If level changed, we might lost one edge
+ * interrupt, raised it through soft-irq.
+ */
+ if (start_level != curr_level)
+ mtk_eint_soft_set(eint, eint_num);
+ }
+
+ if (eint->pins[eint_num].debounce)
+ mtk_eint_debounce_process(eint, eint_num);
- if (index < eint->hw->db_cnt)
- mtk_eint_debounce_process(eint, index);
+ }
}
}
chained_irq_exit(chip, desc);
@@ -403,7 +572,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -411,7 +593,20 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
int mtk_eint_do_resume(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -420,27 +615,45 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
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,
+ int virq, eint_ofset;
+ unsigned int set_ofset, bit, clr_bit, clr_ofset, rst, i, unmask,
dbnc;
+ static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
+ 20000, 40000, 80000, 160000, 320000, 640000 };
struct irq_data *d;
+ unsigned int instance, index;
+ void __iomem *reg;
- if (!eint->hw->db_time)
- return -EOPNOTSUPP;
+ /*
+ * Due to different number of bit field, we only decode
+ * the coordinate here, instead of get the VA.
+ */
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, eint_num);
+ return 0;
+ }
virq = irq_find_mapping(eint->domain, eint_num);
- eint_offset = (eint_num % 4) * 8;
+ eint_ofset = (index % REG_OFSET) * DB_GROUP;
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;
+ reg = eint->instances[instance].base;
+ set_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ clr_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
- dbnc = eint->num_db_time;
- for (i = 0; i < eint->num_db_time; i++) {
- if (debounce <= eint->hw->db_time[i]) {
+ /*
+ * Check eint number to avoid access out-of-range
+ */
+ dbnc = ARRAY_SIZE(debounce_time) - 1;
+ for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+ if (debounce <= debounce_time[i]) {
dbnc = i;
break;
}
@@ -449,23 +662,20 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
if (!mtk_eint_get_mask(eint, eint_num)) {
mtk_eint_mask(d);
unmask = 1;
- } else {
+ } else
unmask = 0;
- }
- clr_bit = 0xff << eint_offset;
- writel(clr_bit, eint->base + clr_offset);
+ clr_bit = 0xff << eint_ofset;
+ writel(clr_bit, reg + clr_ofset);
- 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);
+ bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS)
+ | MTK_EINT_DBNC_SET_EN) << eint_ofset;
+ rst = MTK_EINT_DBNC_RST_BIT << eint_ofset;
+ writel(rst | bit, reg + set_ofset);
/*
- * Delay a while (more than 2T) to wait for hw debounce counter reset
- * work correctly.
+ * Delay should be (8T @ 32k) from dbc rst to work correctly.
*/
- udelay(1);
if (unmask == 1)
mtk_eint_unmask(d);
@@ -473,6 +683,53 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
}
EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
+unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, bit;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
+
+ return (readl(reg) & bit) ? 1 : 0;
+}
+
+unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, mask, ofset;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ ofset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % REG_OFSET) * DB_GROUP);
+ mask = 0xf << ofset;
+
+ return ((readl(reg) & mask) >> ofset);
+}
+
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
int irq;
@@ -485,45 +742,208 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
}
EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
+static const struct mtk_eint_compatible default_compat = {
+ .regs = &mtk_generic_eint_regs,
+};
+
+static const struct of_device_id eint_compatible_ids[] = {
+ { }
+};
+
int mtk_eint_do_init(struct mtk_eint *eint)
{
- int i;
+ int i, virq;
+ unsigned int size;
+ eint->instance_number = 1;
+
+ for (i = 0; i < eint->total_pin_number; i++) {
+ eint->pins[i].enabled = true;
+ eint->pins[i].instance = 0;
+ eint->pins[i].index = i;
+ eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
+
+ eint->instances[0].pin_list[i] = i;
+ eint->instances[0].number++;
+ }
- /* If clients don't assign a specific regs, let's use generic one */
- if (!eint->regs)
- eint->regs = &mtk_generic_eint_regs;
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
- eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->wake_mask), GFP_KERNEL);
- if (!eint->wake_mask)
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
+ eint->domain = irq_domain_add_linear(eint->dev->of_node,
+ eint->total_pin_number,
+ &irq_domain_simple_ops, NULL);
+ if (!eint->domain)
return -ENOMEM;
- eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->cur_mask), GFP_KERNEL);
- if (!eint->cur_mask)
+ mtk_eint_hw_init(eint);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ 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);
+
+ global_eintc = eint;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+
+int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ int i, virq, matrix_number = 0;
+ struct device_node *node;
+ unsigned int ret, size, ofset;
+ unsigned int id, inst, idx, support_deb;
+
+ const phandle *ph;
+
+ ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
+ if (!ph) {
+ dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
+ return -ENODEV;
+ }
+
+ node = of_find_node_by_phandle(be32_to_cpup(ph));
+ if (!node) {
+ dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(node, "mediatek,total-pin-number",
+ &eint->total_pin_number);
+ if (ret) {
+ dev_err(eint->dev,
+ "%s cannot read total-pin-number from device node.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
+ eint->total_pin_number);
+
+ ret = of_property_read_u32(node, "mediatek,instance-num",
+ &eint->instance_number);
+ if (ret)
+ eint->instance_number = 1; // only 1 instance in legacy chip
+
+ size = eint->instance_number * sizeof(struct mtk_eint_instance);
+ eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->instances)
return -ENOMEM;
- eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
- sizeof(int), GFP_KERNEL);
- if (!eint->dual_edge)
+ size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
+ eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->pins)
return -ENOMEM;
+ for (i = 0; i < eint->instance_number; i++) {
+ ret = of_property_read_string_index(node, "reg-name", i,
+ &(eint->instances[i].name));
+ if (ret) {
+ dev_info(eint->dev,
+ "%s cannot read the name of instance %d.\n",
+ __func__, i);
+ }
+
+ eint->instances[i].base = of_iomap(node, i);
+ if (!eint->instances[i].base)
+ return -ENOMEM;
+ }
+
+ matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
+ if (matrix_number < 0) {
+ matrix_number = eint->total_pin_number;
+ dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+ } else
+ dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+
+ for (i = 0; i < matrix_number; i++) {
+ ofset = i * REG_OFSET;
+
+ ret = of_property_read_u32_index(node, "mediatek,pins",
+ ofset, &id);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+FIRST, &inst);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+SECOND, &idx);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+THIRD, &support_deb);
+
+ /* Legacy chip which no need to give coordinate list */
+ if (ret) {
+ id = i;
+ inst = 0;
+ idx = i;
+ support_deb = (i < MAX_BIT) ? 1 : 0;
+ }
+
+ eint->pins[id].enabled = true;
+ eint->pins[id].instance = inst;
+ eint->pins[id].index = idx;
+ eint->pins[id].debounce = support_deb;
+
+ eint->instances[inst].pin_list[idx] = id;
+ eint->instances[inst].number++;
+
+#if defined(MTK_EINT_DEBUG)
+ pin = eint->pins[id];
+ dev_info(eint->dev,
+ "EINT%u in (%u-%u), su_deb = %u",
+ id,
+ pin.instance,
+ eint->instances[inst].number,
+ pin.debounce,
+#endif
+ }
+
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
+ eint->irq = irq_of_parse_and_map(node, 0);
+ if (!eint->irq) {
+ dev_err(eint->dev,
+ "%s IRQ parse fail.\n", __func__);
+ return -EINVAL;
+ }
+
eint->domain = irq_domain_add_linear(eint->dev->of_node,
- eint->hw->ap_num,
+ eint->total_pin_number,
&irq_domain_simple_ops, NULL);
if (!eint->domain)
return -ENOMEM;
- if (eint->hw->db_time) {
- for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
- if (eint->hw->db_time[i] == 0)
- break;
- eint->num_db_time = i;
- }
-
mtk_eint_hw_init(eint);
- for (i = 0; i < eint->hw->ap_num; i++) {
- int virq = irq_create_mapping(eint->domain, i);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ virq = irq_create_mapping(eint->domain, i);
irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
handle_level_irq);
@@ -533,9 +953,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)
irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
eint);
+ global_eintc = eint;
+
return 0;
}
-EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+EXPORT_SYMBOL_GPL(mtk_eint_do_init_v2);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MediaTek EINT Driver");
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 6139b16cd225..aa17a6073029 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -11,6 +11,25 @@
#include <linux/irqdomain.h>
+#define MAX_PIN 999
+#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)
+#define MTK_EINT_NO_OFSET 0
+#define MAX_BIT 32
+#define REG_OFSET 4
+#define REG_GROUP 5
+#define REG_VAL 0xFFFFFFFF
+#define DB_GROUP 8
+#define FIRST 1
+#define SECOND 2
+#define THIRD 3
+#define ARRAY_0 4
+
+//#define MTK_EINT_DEBUG
+
struct mtk_eint_regs {
unsigned int stat;
unsigned int ack;
@@ -30,6 +49,36 @@ struct mtk_eint_regs {
unsigned int dbnc_ctrl;
unsigned int dbnc_set;
unsigned int dbnc_clr;
+ unsigned int event;
+ unsigned int event_set;
+ unsigned int event_clr;
+ unsigned int raw_stat;
+};
+
+struct mtk_eint_ops {
+ void (*ack)(struct irq_data *d);
+};
+
+struct mtk_eint_compatible {
+ struct mtk_eint_ops ops;
+ const struct mtk_eint_regs *regs;
+};
+
+struct mtk_eint_instance {
+ const char *name;
+ void __iomem *base;
+ unsigned int number;
+ unsigned int pin_list[MAX_PIN];
+ unsigned int *wake_mask;
+ unsigned int *cur_mask;
+};
+
+struct mtk_eint_pin {
+ bool enabled;
+ unsigned int instance;
+ unsigned int index;
+ bool debounce;
+ bool dual_edge;
};
struct mtk_eint_hw {
@@ -60,11 +109,14 @@ struct mtk_eint {
struct irq_domain *domain;
int irq;
- int *dual_edge;
- u32 *wake_mask;
- u32 *cur_mask;
-
- /* Used to fit into various EINT device */
+ /* An array to record the coordinate, index by global EINT ID */
+ struct mtk_eint_pin *pins;
+ /* An array to record the global EINT ID, index by coordinate*/
+ struct mtk_eint_instance *instances;
+ unsigned int total_pin_number;
+ unsigned int instance_number;
+ unsigned int dump_target_eint;
+ const struct mtk_eint_compatible *comp;
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
u16 num_db_time;
@@ -74,13 +126,15 @@ struct mtk_eint {
const struct mtk_eint_xt *gpio_xlate;
};
-#if IS_ENABLED(CONFIG_EINT_MTK)
+#if (IS_ENABLED(CONFIG_EINT_MTK) || IS_ENABLED(CONFIG_DEVICE_MODULES_EINT_MTK))
int mtk_eint_do_init(struct mtk_eint *eint);
+int mtk_eint_do_init_v2(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);
+int dump_eint_pin_status(unsigned int eint_num);
#else
static inline int mtk_eint_do_init(struct mtk_eint *eint)
@@ -88,6 +142,11 @@ static inline int mtk_eint_do_init(struct mtk_eint *eint)
return -EOPNOTSUPP;
}
+static inline int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
@@ -108,5 +167,9 @@ static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
return -EOPNOTSUPP;
}
+static inline int dump_eint_pin_status(unsigned int eint_num)
+{
+ return -EOPNOTSUPP;
+}
#endif
#endif /* __MTK_EINT_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index 54301fbba524..3740e868c650 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -375,33 +375,37 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
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;
-
- hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
- if (IS_ERR(hw->eint->base)) {
- ret = PTR_ERR(hw->eint->base);
- goto err_free_eint;
- }
+ if (hw->soc->eint_hw) {
+ hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
+ if (!hw->eint)
+ return -ENOMEM;
+
+ hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
+ if (IS_ERR(hw->eint->base)) {
+ ret = PTR_ERR(hw->eint->base);
+ goto err_free_eint;
+ }
- hw->eint->irq = irq_of_parse_and_map(np, 0);
- if (!hw->eint->irq) {
- ret = -EINVAL;
- goto err_free_eint;
- }
+ hw->eint->irq = irq_of_parse_and_map(np, 0);
+ if (!hw->eint->irq) {
+ ret = -EINVAL;
+ goto err_free_eint;
+ }
- if (!hw->soc->eint_hw) {
- ret = -ENODEV;
- goto err_free_eint;
- }
+ 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);
- hw->eint->dev = &pdev->dev;
- hw->eint->hw = hw->soc->eint_hw;
- hw->eint->pctl = hw;
- hw->eint->gpio_xlate = &mtk_eint_xt;
+ } else {
+ hw->eint->dev = &pdev->dev;
+ hw->eint->pctl = hw;
+ hw->eint->gpio_xlate = &mtk_eint_xt;
- return mtk_eint_do_init(hw->eint);
+ return mtk_eint_do_init_v2(hw->eint);
+ }
err_free_eint:
devm_kfree(hw->dev, hw->eint);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
2024-10-24 14:15 chang hao
@ 2024-10-24 15:55 ` AngeloGioacchino Del Regno
[not found] ` <2d385d533e8f0f23cedad22d4ef46ed4f6550f31.camel@mediatek.com>
0 siblings, 1 reply; 13+ messages in thread
From: AngeloGioacchino Del Regno @ 2024-10-24 15:55 UTC (permalink / raw)
To: chang hao, matthias.bgg, sean.wang, linus.walleij
Cc: linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel
Il 24/10/24 16:15, chang hao ha scritto:
> From: Chhao Chang <ot_chhao.chang@mediatek.com>
>
> eint is divided from the original base address into base addresses
> in five directions: east, south, west, north, and center.
> Stores a limited number of eint numbers in each direction.
>
> Signed-off-by: Chhao Chang <ot_chhao.chang@mediatek.com>
> ---
> drivers/pinctrl/mediatek/mtk-eint.c | 830 +++++++++++++-----
> drivers/pinctrl/mediatek/mtk-eint.h | 75 +-
> .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 50 +-
> 3 files changed, 722 insertions(+), 233 deletions(-)
>
> diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
> index 27f0a54e12bf..0bb017eb1893 100644
> --- a/drivers/pinctrl/mediatek/mtk-eint.c
> +++ b/drivers/pinctrl/mediatek/mtk-eint.c
> @@ -17,16 +17,13 @@
> #include <linux/irqdomain.h>
> #include <linux/module.h>
> #include <linux/of_irq.h>
> +#include <linux/of_address.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_MAX 16
> -#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
> -#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
> +static struct mtk_eint *global_eintc;
> +struct mtk_eint_pin pin;
Noupe, don't introduce these globals.
>
> static const struct mtk_eint_regs mtk_generic_eint_regs = {
> .stat = 0x000,
> @@ -47,6 +44,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
> .dbnc_ctrl = 0x500,
> .dbnc_set = 0x600,
> .dbnc_clr = 0x700,
> + .event = 0x800,
> + .event_set = 0x840,
> + .event_clr = 0x880,
> + .raw_stat = 0xa00,
> };
>
> const unsigned int debounce_time_mt2701[] = {
> @@ -64,60 +65,145 @@ const unsigned int debounce_time_mt6795[] = {
> };
> EXPORT_SYMBOL_GPL(debounce_time_mt6795);
>
> -static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
> +/*
> + * Return the iomem of specific register ofset and decode the coordinate
> + * (instance, index) from global eint number.
> + * If return NULL, then it must be either out-of-range or do-not-support.
> + */
> +static void __iomem *mtk_eint_get_ofset(struct mtk_eint *eint,
You're replacing this with a typo....
> unsigned int eint_num,
> - unsigned int offset)
> + unsigned int ofset,
and you're typoing offset on purpose again?! :-\
> + unsigned int *instance,
> + unsigned int *index)
> {
> - unsigned int eint_base = 0;
> void __iomem *reg;
>
> - if (eint_num >= eint->hw->ap_num)
> - eint_base = eint->hw->ap_num;
> + if (eint_num >= eint->total_pin_number ||
> + !eint->pins[eint_num].enabled) {
> + WARN_ON(1);
> + return NULL;
> + }
>
> - reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
> + *instance = eint->pins[eint_num].instance;
> + *index = eint->pins[eint_num].index;
> + reg = eint->instances[*instance].base + ofset + (*index / MAX_BIT * REG_OFSET);
>
> return reg;
> }
>
> +/*
> + * Generate helper function to access property register of a dedicate pin.
> + */
...and you don't need this (sorry, ugly!) macro either, as this is only
helping you to create a mass-duplication situation here.
If you need a helper, write *one* function that retrieves the data for you
from a chosen register.
> +#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFSET) \
> +static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
> + unsigned int eint_num) \
> +{ \
> + unsigned int instance, index; \
> + void __iomem *reg = mtk_eint_get_ofset(eint, eint_num, \
> + _OFSET, \
> + &instance, &index); \
> + unsigned int bit = BIT(index & 0x1f);\
> +\
> + if (!reg) { \
> + dev_err(eint->dev, "%s invalid eint_num %d\n", \
> + __func__, eint_num); \
> + return 0;\
> + } \
> +\
> + return !!(readl(reg) & bit); \
> +}
> +
> +DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
> +DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
> +DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
> +DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
> +DEFINE_EINT_GET_FUNCTION(dom_en, eint->comp->regs->dom_en);
> +DEFINE_EINT_GET_FUNCTION(event, eint->comp->regs->event);
> +DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
> +
> +int dump_eint_pin_status(unsigned int eint_num)
I don't think that this is necessary... also because, there's already irq/debugfs.c
for debugging. If you really need debug, hook it to the right APIs.
> +{
> + unsigned int stat, raw_stat, mask, sens, pol, dom_en, event;
> +
> + if (eint_num < 0 || eint_num > global_eintc->total_pin_number)
> + return ENODEV;
> +
> + stat = mtk_eint_get_stat(global_eintc, eint_num);
> + raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
> + mask = mtk_eint_get_mask(global_eintc, eint_num);
> + sens = mtk_eint_get_sens(global_eintc, eint_num);
> + pol = mtk_eint_get_pol(global_eintc, eint_num);
> + dom_en = mtk_eint_get_dom_en(global_eintc, eint_num);
> + event = mtk_eint_get_event(global_eintc, eint_num);
> + dev_info(global_eintc->dev, "%s eint_num:%u=stat:%u,raw:%u, \
> + mask:%u, sens:%u,pol:%u,dom_en:%u,event:%u\n",
> + __func__, eint_num, stat, raw_stat, mask, sens,
> + pol, dom_en, event);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(dump_eint_pin_status);
> +
> 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);
> + unsigned int instance, index;
> + void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
> + eint->comp->regs->sens,
> + &instance, &index);
> + unsigned int bit = BIT(index & 0x1f);
I'm not sure why you can't use BIT(eint_num % 32) anymore.
Even though your EINT is split in 5, that should be still aligned the same as
the "old" EINT.
> +
> + if (!reg) {
That won't ever happen, because you're already checking that in callers of
this function, hence this check is redundant, or looks like it is anyway.
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return 0;
> + }
>
> 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)
> + if (eint->pins[eint_num].debounce &&
> + sens != MTK_EINT_EDGE_SENSITIVE)
> return 1;
> else
> return 0;
> }
>
> -static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
> +static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)
Why are you changing the parameter name from hwirq to eint_num?!
> {
> 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);
> + unsigned int reg_ofset;
> + unsigned int instance, index, mask, port;
> + void __iomem *reg;
>
> - curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
> + reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %d\n",
> + __func__, eint_num);
> + return 0;
> + }
> +
> + mask = BIT(index & 0x1f);
> + port = index >> REG_GROUP;
> + reg = eint->instances[instance].base + port * REG_OFSET;
> +
..snip..
> @@ -403,7 +572,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
>
> int mtk_eint_do_suspend(struct mtk_eint *eint)
> {
> - mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
> + unsigned int i, j, port;
> +
> + for (i = 0; i < eint->instance_number; i++) {
> + struct mtk_eint_instance inst = eint->instances[i];
Just register five different instances if they really have to be separated,
which I don't believe they do, anyway.
You should really read what mtk_eint_hw is for.
> +
> + for (j = 0; j < inst.number; j += MAX_BIT) {
> + port = j >> REG_GROUP;
> + writel_relaxed(~inst.wake_mask[port],
> + inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
> + writel_relaxed(inst.wake_mask[port],
> + inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
> + }
> + }
> + dsb(sy);
>
> return 0;
> }
..snip..
> @@ -420,27 +615,45 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
> 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,
> + int virq, eint_ofset;
> + unsigned int set_ofset, bit, clr_bit, clr_ofset, rst, i, unmask,
> dbnc;
> + static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
> + 20000, 40000, 80000, 160000, 320000, 640000 };
This is another mtk_eint_hw array that you're carelessly hardcoding inside of the
eint driver.
> struct irq_data *d;
> + unsigned int instance, index;
> + void __iomem *reg;
>
> - if (!eint->hw->db_time)
> - return -EOPNOTSUPP;
> + /*
> + * Due to different number of bit field, we only decode
> + * the coordinate here, instead of get the VA.
> + */
> + reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
> + &instance, &index);
> +
> + if (!reg) {
> + dev_err(eint->dev, "%s invalid eint_num %lu\n",
> + __func__, eint_num);
> + return 0;
> + }
>
> virq = irq_find_mapping(eint->domain, eint_num);
> - eint_offset = (eint_num % 4) * 8;
> + eint_ofset = (index % REG_OFSET) * DB_GROUP;
> 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;
> + reg = eint->instances[instance].base;
> + set_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
> + clr_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_clr;
>
> if (!mtk_eint_can_en_debounce(eint, eint_num))
> return -EINVAL;
>
> - dbnc = eint->num_db_time;
> - for (i = 0; i < eint->num_db_time; i++) {
> - if (debounce <= eint->hw->db_time[i]) {
> + /*
> + * Check eint number to avoid access out-of-range
> + */
> + dbnc = ARRAY_SIZE(debounce_time) - 1;
And here, you carelessly break every other supported MediaTek SoC.
> + for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
> + if (debounce <= debounce_time[i]) {
> dbnc = i;
> break;
> }
..snip..
> +
> +int mtk_eint_do_init_v2(struct mtk_eint *eint)
> +{
> + int i, virq, matrix_number = 0;
> + struct device_node *node;
> + unsigned int ret, size, ofset;
> + unsigned int id, inst, idx, support_deb;
> +
> + const phandle *ph;
> +
> + ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
No, a SoC always has the same eint controller(s), always mapped to the same pins.
This is not something for devicetree - but rather something that was already
resolved in the past, when `struct mtk_eint_hw` was introduced.
You should just look at how this driver works upstream and implement support for
the new EINT in there.... not by copy-pasting something from downstream to upstream
and expecting it to be accepted.
> + if (!ph) {
> + dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
> + return -ENODEV;
> + }
> +
> + node = of_find_node_by_phandle(be32_to_cpup(ph));
> + if (!node) {
> + dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
> + return -ENODEV;
> + }
> +
> + ret = of_property_read_u32(node, "mediatek,total-pin-number",
> + &eint->total_pin_number);
eint_hw->ap_num is the same thing as this.
> + if (ret) {
> + dev_err(eint->dev,
> + "%s cannot read total-pin-number from device node.\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
> + eint->total_pin_number);
> +
> + ret = of_property_read_u32(node, "mediatek,instance-num",
> + &eint->instance_number);
> + if (ret)
> + eint->instance_number = 1; // only 1 instance in legacy chip
> +
> + size = eint->instance_number * sizeof(struct mtk_eint_instance);
> + eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
> + if (!eint->instances)
> return -ENOMEM;
>
> - eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
> - sizeof(int), GFP_KERNEL);
> - if (!eint->dual_edge)
> + size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
> + eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
> + if (!eint->pins)
> return -ENOMEM;
>
> + for (i = 0; i < eint->instance_number; i++) {
> + ret = of_property_read_string_index(node, "reg-name", i,
> + &(eint->instances[i].name));
> + if (ret) {
> + dev_info(eint->dev,
> + "%s cannot read the name of instance %d.\n",
> + __func__, i);
> + }
> +
> + eint->instances[i].base = of_iomap(node, i);
> + if (!eint->instances[i].base)
> + return -ENOMEM;
> + }
> +
> + matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
> + if (matrix_number < 0) {
> + matrix_number = eint->total_pin_number;
> + dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
> + __func__, matrix_number);
> + } else
> + dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
> + __func__, matrix_number);
> +
> + for (i = 0; i < matrix_number; i++) {
> + ofset = i * REG_OFSET;
> +
> + ret = of_property_read_u32_index(node, "mediatek,pins",
> + ofset, &id);
So basically this means that if a SoC has 200 EINT pins, you'll have 200 values
in devicetree?!
> + ret |= of_property_read_u32_index(node, "mediatek,pins",
> + ofset+FIRST, &inst);
> + ret |= of_property_read_u32_index(node, "mediatek,pins",
> + ofset+SECOND, &idx);
> + ret |= of_property_read_u32_index(node, "mediatek,pins",
> + ofset+THIRD, &support_deb);
> +
> + /* Legacy chip which no need to give coordinate list */
> + if (ret) {
> + id = i;
> + inst = 0;
> + idx = i;
> + support_deb = (i < MAX_BIT) ? 1 : 0;
> + }
> +
> + eint->pins[id].enabled = true;
> + eint->pins[id].instance = inst;
> + eint->pins[id].index = idx;
> + eint->pins[id].debounce = support_deb;
> +
> + eint->instances[inst].pin_list[idx] = id;
> + eint->instances[inst].number++;
> +
..snip..
> diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
> index 6139b16cd225..aa17a6073029 100644
> --- a/drivers/pinctrl/mediatek/mtk-eint.h
> +++ b/drivers/pinctrl/mediatek/mtk-eint.h
> @@ -11,6 +11,25 @@
>
> #include <linux/irqdomain.h>
>
> +#define MAX_PIN 999
> +#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)
> +#define MTK_EINT_NO_OFSET 0
> +#define MAX_BIT 32
MAX_BIT==32? Ok, so I was right in saying that the new eint is just the old one
but with more than one instance.
> +#define REG_OFSET 4
> +#define REG_GROUP 5
> +#define REG_VAL 0xFFFFFFFF
> +#define DB_GROUP 8
> +#define FIRST 1
> +#define SECOND 2
> +#define THIRD 3
> +#define ARRAY_0 4
> +
> +//#define MTK_EINT_DEBUG
Those definitions are either cryptic or unneeded.
And I'll stop my review here.
To be clear, the response is a huge "NACK"; you really have to redo everything
from scratch, but this time, just implement support for the new design on the base
of this upstream driver.
Regards,
Angelo
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH] pinctrl: mediatek: add eint new design for mt8196
@ 2024-10-24 12:21 chang hao
0 siblings, 0 replies; 13+ messages in thread
From: chang hao @ 2024-10-24 12:21 UTC (permalink / raw)
To: matthias.bgg, angelogioacchino.delregno, sean.wang, linus.walleij
Cc: linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel,
Chhao Chang
From: Chhao Chang <ot_chhao.chang@mediatek.com>
eint is divided from the original base address into base addresses
in five directions: east, south, west, north, and center.
Stores a limited number of eint numbers in each direction.
Signed-off-by: Chhao Chang <ot_chhao.chang@mediatek.com>
---
drivers/pinctrl/mediatek/mtk-eint.c | 835 +++++++++++++-----
drivers/pinctrl/mediatek/mtk-eint.h | 75 +-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 26 +-
3 files changed, 701 insertions(+), 235 deletions(-)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 27f0a54e12bf..edfd684530ab 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -17,16 +17,13 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of_irq.h>
+#include <linux/of_address.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_MAX 16
-#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
-#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
+static struct mtk_eint *global_eintc;
+struct mtk_eint_pin pin;
static const struct mtk_eint_regs mtk_generic_eint_regs = {
.stat = 0x000,
@@ -47,6 +44,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
+ .event = 0x800,
+ .event_set = 0x840,
+ .event_clr = 0x880,
+ .raw_stat = 0xa00,
};
const unsigned int debounce_time_mt2701[] = {
@@ -64,60 +65,145 @@ const unsigned int debounce_time_mt6795[] = {
};
EXPORT_SYMBOL_GPL(debounce_time_mt6795);
-static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
+/*
+ * Return the iomem of specific register ofset and decode the coordinate
+ * (instance, index) from global eint number.
+ * If return NULL, then it must be either out-of-range or do-not-support.
+ */
+static void __iomem *mtk_eint_get_ofset(struct mtk_eint *eint,
unsigned int eint_num,
- unsigned int offset)
+ unsigned int ofset,
+ unsigned int *instance,
+ unsigned int *index)
{
- unsigned int eint_base = 0;
void __iomem *reg;
- if (eint_num >= eint->hw->ap_num)
- eint_base = eint->hw->ap_num;
+ if (eint_num >= eint->total_pin_number ||
+ !eint->pins[eint_num].enabled) {
+ WARN_ON(1);
+ return NULL;
+ }
- reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+ *instance = eint->pins[eint_num].instance;
+ *index = eint->pins[eint_num].index;
+ reg = eint->instances[*instance].base + ofset + (*index / MAX_BIT * REG_OFSET);
return reg;
}
+/*
+ * Generate helper function to access property register of a dedicate pin.
+ */
+#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFSET) \
+static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
+ unsigned int eint_num) \
+{ \
+ unsigned int instance, index; \
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num, \
+ _OFSET, \
+ &instance, &index); \
+ unsigned int bit = BIT(index & 0x1f);\
+\
+ if (!reg) { \
+ dev_err(eint->dev, "%s invalid eint_num %d\n", \
+ __func__, eint_num); \
+ return 0;\
+ } \
+\
+ return !!(readl(reg) & bit); \
+}
+
+DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
+DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
+DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
+DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
+DEFINE_EINT_GET_FUNCTION(dom_en, eint->comp->regs->dom_en);
+DEFINE_EINT_GET_FUNCTION(event, eint->comp->regs->event);
+DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
+
+int dump_eint_pin_status(unsigned int eint_num)
+{
+ unsigned int stat, raw_stat, mask, sens, pol, dom_en, event;
+
+ if (eint_num < 0 || eint_num > global_eintc->total_pin_number)
+ return ENODEV;
+
+ stat = mtk_eint_get_stat(global_eintc, eint_num);
+ raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
+ mask = mtk_eint_get_mask(global_eintc, eint_num);
+ sens = mtk_eint_get_sens(global_eintc, eint_num);
+ pol = mtk_eint_get_pol(global_eintc, eint_num);
+ dom_en = mtk_eint_get_dom_en(global_eintc, eint_num);
+ event = mtk_eint_get_event(global_eintc, eint_num);
+ dev_info(global_eintc->dev, "%s eint_num:%u=stat:%u,raw:%u, \
+ mask:%u, sens:%u,pol:%u,dom_en:%u,event:%u\n",
+ __func__, eint_num, stat, raw_stat, mask, sens,
+ pol, dom_en, event);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dump_eint_pin_status);
+
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->sens,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
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)
+ if (eint->pins[eint_num].debounce &&
+ sens != MTK_EINT_EDGE_SENSITIVE)
return 1;
else
return 0;
}
-static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)
{
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);
+ unsigned int reg_ofset;
+ unsigned int instance, index, mask, port;
+ void __iomem *reg;
- curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ mask = BIT(index & 0x1f);
+ port = index >> REG_GROUP;
+ reg = eint->instances[instance].base + port * REG_OFSET;
+
+ curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, eint_num);
do {
start_level = curr_level;
if (start_level)
- reg_offset = eint->regs->pol_clr;
+ reg_ofset = eint->comp->regs->pol_clr;
else
- reg_offset = eint->regs->pol_set;
- writel(mask, reg + reg_offset);
+ reg_ofset = eint->comp->regs->pol_set;
+
+ writel(mask, reg + reg_ofset);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
- hwirq);
+ eint_num);
} while (start_level != curr_level);
return start_level;
@@ -126,11 +212,19 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_set,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] &= ~mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] &= ~mask;
writel(mask, reg);
}
@@ -138,43 +232,91 @@ static void mtk_eint_mask(struct irq_data *d)
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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->mask_clr,
+ &instance, &index);
+ u32 mask = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
- eint->cur_mask[d->hwirq >> 5] |= mask;
+ eint->instances[instance].cur_mask[index >> REG_GROUP] |= mask;
writel(mask, reg);
- if (eint->dual_edge[d->hwirq])
+ if (eint->pins[d->hwirq].dual_edge)
mtk_eint_flip_edge(eint, d->hwirq);
}
-static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
+static void mtk_eint_ack(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ unsigned int instance, index;
+ void __iomem *reg;
+ unsigned int bit;
+
+ if (eint->comp->ops.ack)
+ eint->comp->ops.ack(d);
+ else {
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->ack,
+ &instance, &index);
+ bit = BIT(index & 0x1f);
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return;
+ }
+
+ writel(bit, reg);
+ }
+}
+
+static void mtk_eint_soft_set(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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_set,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- return !!(readl(reg) & bit);
+ writel(bit, reg);
}
-static void mtk_eint_ack(struct irq_data *d)
+static void mtk_eint_soft_clr(struct mtk_eint *eint,
+ unsigned int eint_num)
{
- 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);
+ unsigned int instance, index;
+ void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+ eint->comp->regs->soft_clr,
+ &instance, &index);
+ unsigned int bit = BIT(index & 0x1f);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
- writel(mask, reg);
+ writel(bit, 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);
- bool masked;
- u32 mask = BIT(d->hwirq & 0x1f);
+ u32 mask;
+ unsigned int instance, index;
void __iomem *reg;
if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
@@ -186,36 +328,42 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
}
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- eint->dual_edge[d->hwirq] = 1;
+ eint->pins[d->hwirq].dual_edge = 1;
else
- eint->dual_edge[d->hwirq] = 0;
+ eint->pins[d->hwirq].dual_edge = 0;
- if (!mtk_eint_get_mask(eint, d->hwirq)) {
- mtk_eint_mask(d);
- masked = false;
- } else {
- masked = true;
- }
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->pol_set,
+ &instance, &index);
- 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);
- }
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_clr,
+ &instance, &index);
+ else
+ reg = mtk_eint_get_ofset(eint, d->hwirq,
+ eint->comp->regs->sens_set,
+ &instance, &index);
- 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 (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
}
- mtk_eint_ack(d);
- if (!masked)
- mtk_eint_unmask(d);
+ mask = BIT(index & 0x1f);
+ writel(mask, reg);
+
+ if (eint->pins[d->hwirq].dual_edge)
+ mtk_eint_flip_edge(eint, d->hwirq);
return 0;
}
@@ -223,30 +371,28 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
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;
+ unsigned int instance, index, shift, port;
+ void __iomem *reg = mtk_eint_get_ofset(eint, d->hwirq,
+ MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, d->hwirq);
+ return 0;
+ }
+
+ shift = index & 0x1f;
+ port = index >> REG_GROUP;
if (on)
- eint->wake_mask[reg] |= BIT(shift);
+ eint->instances[instance].wake_mask[port] |= BIT(shift);
else
- eint->wake_mask[reg] &= ~BIT(shift);
+ eint->instances[instance].wake_mask[port] &= ~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 int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -290,7 +436,7 @@ static void mtk_eint_irq_release_resources(struct irq_data *d)
}
static struct irq_chip mtk_eint_irq_chip = {
- .name = "mt-eint",
+ .name = "mtk-eint",
.irq_disable = mtk_eint_mask,
.irq_mask = mtk_eint_mask,
.irq_unmask = mtk_eint_unmask,
@@ -301,35 +447,51 @@ static struct irq_chip mtk_eint_irq_chip = {
.irq_release_resources = mtk_eint_irq_release_resources,
};
+/*
+ * Configure all EINT pins as domain 0, which only belongs to AP.
+ */
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
- void __iomem *dom_en = eint->base + eint->regs->dom_en;
- void __iomem *mask_set = eint->base + eint->regs->mask_set;
- unsigned int i;
-
- for (i = 0; i < eint->hw->ap_num; i += 32) {
- writel(0xffffffff, dom_en);
- writel(0xffffffff, mask_set);
- dom_en += 4;
- mask_set += 4;
+ void __iomem *reg,*eevt_clr;
+ unsigned int i, j;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ reg = eint->instances[i].base + eint->comp->regs->dom_en;
+ eevt_clr = eint->instances[i].base + eint->comp->regs->event_clr;
+ for (j = 0; j < eint->instances[i].number; j += MAX_BIT, reg += REG_OFSET, eevt_clr += REG_OFSET) {
+ writel(REG_VAL, reg);
+ writel(REG_VAL, eevt_clr);
+ }
}
return 0;
}
static inline void
-mtk_eint_debounce_process(struct mtk_eint *eint, int index)
+mtk_eint_debounce_process(struct mtk_eint *eint, int eint_num)
{
- unsigned int rst, ctrl_offset;
+ unsigned int rst, ctrl_ofset;
unsigned int bit, dbnc;
+ unsigned int instance, index;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return;
+ }
+
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+ dbnc = readl(eint->instances[instance].base + ctrl_ofset);
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
- 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);
+ ctrl_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ rst = MTK_EINT_DBNC_RST_BIT << ((index % REG_OFSET) * DB_GROUP);
+ writel(rst, eint->instances[instance].base + ctrl_ofset);
}
}
@@ -337,65 +499,72 @@ 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, mask_offset, index;
- void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
- int dual_edge, start_level, curr_level;
+ unsigned int status, i, j;
+ int shift, port, eint_num, virq;
+ unsigned int dual_edge, start_level, curr_level;
+ struct mtk_eint_instance eint_instance;
+ void __iomem *addr;
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);
- mask_offset = eint_num >> 5;
- index = eint_num + offset;
- status &= ~BIT(offset);
-
- /*
- * If we get an interrupt on pin that was only required
- * for wake (but no real interrupt requested), mask the
- * interrupt (as would mtk_eint_resume do anyway later
- * in the resume sequence).
- */
- if (eint->wake_mask[mask_offset] & BIT(offset) &&
- !(eint->cur_mask[mask_offset] & BIT(offset))) {
- writel_relaxed(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->mask_set);
- }
-
- 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);
- }
+ for (i = 0; i < eint->instance_number; i++) {
+ eint_instance = eint->instances[i];
- generic_handle_domain_irq(eint->domain, index);
+ /* Iterate all pins by port */
+ for (j = 0; j < eint_instance.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ status = readl(eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->stat);
+ while (status) {
+ shift = __ffs(status);
+ status &= ~BIT(shift);
- if (dual_edge) {
- curr_level = mtk_eint_flip_edge(eint, index);
+ eint_num = eint->instances[i].pin_list[shift + j];
+ virq = irq_find_mapping(eint->domain, eint_num);
/*
- * If level changed, we might lost one edge
- * interrupt, raised it through soft-irq.
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
*/
- if (start_level != curr_level)
- writel(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->soft_set);
- }
+ if (eint->instances[i].wake_mask[port] & BIT(shift) &&
+ !(eint->instances[i].cur_mask[port] & BIT(shift))) {
+ addr = eint_instance.base + port * REG_OFSET +
+ eint->comp->regs->mask_set;
+ writel_relaxed(BIT(shift), addr);
+ }
+
+ dual_edge = eint->pins[eint_num].dual_edge;
+ if (dual_edge) {
+ /*
+ * Clear soft-irq in case we raised it last
+ * time.
+ */
+ mtk_eint_soft_clr(eint, eint_num);
+
+ start_level =
+ eint->gpio_xlate->get_gpio_state(eint->pctl,
+ eint_num);
+ }
+
+ generic_handle_irq(virq);
+
+ if (dual_edge) {
+ curr_level = mtk_eint_flip_edge(eint, eint_num);
+
+ /*
+ * If level changed, we might lost one edge
+ * interrupt, raised it through soft-irq.
+ */
+ if (start_level != curr_level)
+ mtk_eint_soft_set(eint, eint_num);
+ }
+
+ if (eint->pins[eint_num].debounce)
+ mtk_eint_debounce_process(eint, eint_num);
- if (index < eint->hw->db_cnt)
- mtk_eint_debounce_process(eint, index);
+ }
}
}
chained_irq_exit(chip, desc);
@@ -403,7 +572,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.wake_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -411,7 +593,20 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
int mtk_eint_do_resume(struct mtk_eint *eint)
{
- mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
+ unsigned int i, j, port;
+
+ for (i = 0; i < eint->instance_number; i++) {
+ struct mtk_eint_instance inst = eint->instances[i];
+
+ for (j = 0; j < inst.number; j += MAX_BIT) {
+ port = j >> REG_GROUP;
+ writel_relaxed(~inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+ writel_relaxed(inst.cur_mask[port],
+ inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+ }
+ }
+ dsb(sy);
return 0;
}
@@ -420,27 +615,45 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
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,
+ int virq, eint_ofset;
+ unsigned int set_ofset, bit, clr_bit, clr_ofset, rst, i, unmask,
dbnc;
+ static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
+ 20000, 40000, 80000, 160000, 320000, 640000 };
struct irq_data *d;
+ unsigned int instance, index;
+ void __iomem *reg;
- if (!eint->hw->db_time)
- return -EOPNOTSUPP;
+ /*
+ * Due to different number of bit field, we only decode
+ * the coordinate here, instead of get the VA.
+ */
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %lu\n",
+ __func__, eint_num);
+ return 0;
+ }
virq = irq_find_mapping(eint->domain, eint_num);
- eint_offset = (eint_num % 4) * 8;
+ eint_ofset = (index % REG_OFSET) * DB_GROUP;
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;
+ reg = eint->instances[instance].base;
+ set_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+ clr_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
- dbnc = eint->num_db_time;
- for (i = 0; i < eint->num_db_time; i++) {
- if (debounce <= eint->hw->db_time[i]) {
+ /*
+ * Check eint number to avoid access out-of-range
+ */
+ dbnc = ARRAY_SIZE(debounce_time) - 1;
+ for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+ if (debounce <= debounce_time[i]) {
dbnc = i;
break;
}
@@ -449,23 +662,20 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
if (!mtk_eint_get_mask(eint, eint_num)) {
mtk_eint_mask(d);
unmask = 1;
- } else {
+ } else
unmask = 0;
- }
- clr_bit = 0xff << eint_offset;
- writel(clr_bit, eint->base + clr_offset);
+ clr_bit = 0xff << eint_ofset;
+ writel(clr_bit, reg + clr_ofset);
- 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);
+ bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS)
+ | MTK_EINT_DBNC_SET_EN) << eint_ofset;
+ rst = MTK_EINT_DBNC_RST_BIT << eint_ofset;
+ writel(rst | bit, reg + set_ofset);
/*
- * Delay a while (more than 2T) to wait for hw debounce counter reset
- * work correctly.
+ * Delay should be (8T @ 32k) from dbc rst to work correctly.
*/
- udelay(1);
if (unmask == 1)
mtk_eint_unmask(d);
@@ -473,6 +683,53 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
}
EXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
+unsigned int mtk_eint_get_debounce_en(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, bit;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ bit = MTK_EINT_DBNC_SET_EN << ((index % REG_OFSET) * DB_GROUP);
+
+ return (readl(reg) & bit) ? 1 : 0;
+}
+
+unsigned int mtk_eint_get_debounce_value(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int instance, index, mask, ofset;
+ void __iomem *reg;
+
+ reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+ &instance, &index);
+
+ if (!reg) {
+ dev_err(eint->dev, "%s invalid eint_num %d\n",
+ __func__, eint_num);
+ return 0;
+ }
+
+ reg = eint->instances[instance].base +
+ (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_ctrl;
+
+ ofset = MTK_EINT_DBNC_SET_DBNC_BITS + ((index % REG_OFSET) * DB_GROUP);
+ mask = 0xf << ofset;
+
+ return ((readl(reg) & mask) >> ofset);
+}
+
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
int irq;
@@ -485,45 +742,213 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
}
EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
+static const struct mtk_eint_compatible default_compat = {
+ .regs = &mtk_generic_eint_regs,
+};
+
+static const struct of_device_id eint_compatible_ids[] = {
+ { }
+};
+
int mtk_eint_do_init(struct mtk_eint *eint)
{
- int i;
+ int i, virq;
+ unsigned int size;
+ eint->instance_number = 1;
+ dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
+ __func__, eint->instance_number);
+
+ if (eint != NULL && eint->hw != NULL)
+ eint->total_pin_number = eint->hw->ap_num;
+ else
+ dev_info(eint->dev, "%s Error: eint or eint->hw is NULL\n.", __func__);
+
+ for (i = 0; i < eint->total_pin_number; i++) {
+ eint->pins[i].enabled = true;
+ eint->pins[i].instance = 0;
+ eint->pins[i].index = i;
+ eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
+
+ eint->instances[0].pin_list[i] = i;
+ eint->instances[0].number++;
+ }
+
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
- /* If clients don't assign a specific regs, let's use generic one */
- if (!eint->regs)
- eint->regs = &mtk_generic_eint_regs;
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
- eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->wake_mask), GFP_KERNEL);
- if (!eint->wake_mask)
+ eint->domain = irq_domain_add_linear(eint->dev->of_node,
+ eint->total_pin_number,
+ &irq_domain_simple_ops, NULL);
+ if (!eint->domain)
return -ENOMEM;
- eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->cur_mask), GFP_KERNEL);
- if (!eint->cur_mask)
+ mtk_eint_hw_init(eint);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ 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);
+
+ global_eintc = eint;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+
+int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ int i, virq, matrix_number = 0;
+ struct device_node *node;
+ unsigned int ret, size, ofset;
+ unsigned int id, inst, idx, support_deb;
+
+ const phandle *ph;
+
+ ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
+ if (!ph) {
+ dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
+ return -ENODEV;
+ }
+
+ node = of_find_node_by_phandle(be32_to_cpup(ph));
+ if (!node) {
+ dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(node, "mediatek,total-pin-number",
+ &eint->total_pin_number);
+ if (ret) {
+ dev_err(eint->dev,
+ "%s cannot read total-pin-number from device node.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
+ eint->total_pin_number);
+
+ ret = of_property_read_u32(node, "mediatek,instance-num",
+ &eint->instance_number);
+ if (ret)
+ eint->instance_number = 1; // only 1 instance in legacy chip
+
+ size = eint->instance_number * sizeof(struct mtk_eint_instance);
+ eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->instances)
return -ENOMEM;
- eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
- sizeof(int), GFP_KERNEL);
- if (!eint->dual_edge)
+ size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
+ eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->pins)
return -ENOMEM;
+ for (i = 0; i < eint->instance_number; i++) {
+ ret = of_property_read_string_index(node, "reg-name", i,
+ &(eint->instances[i].name));
+ if (ret) {
+ dev_info(eint->dev,
+ "%s cannot read the name of instance %d.\n",
+ __func__, i);
+ }
+
+ eint->instances[i].base = of_iomap(node, i);
+ if (!eint->instances[i].base)
+ return -ENOMEM;
+ }
+
+ matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
+ if (matrix_number < 0) {
+ matrix_number = eint->total_pin_number;
+ dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+ } else
+ dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
+ __func__, matrix_number);
+
+ for (i = 0; i < matrix_number; i++) {
+ ofset = i * REG_OFSET;
+
+ ret = of_property_read_u32_index(node, "mediatek,pins",
+ ofset, &id);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+FIRST, &inst);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+SECOND, &idx);
+ ret |= of_property_read_u32_index(node, "mediatek,pins",
+ ofset+THIRD, &support_deb);
+
+ /* Legacy chip which no need to give coordinate list */
+ if (ret) {
+ id = i;
+ inst = 0;
+ idx = i;
+ support_deb = (i < MAX_BIT) ? 1 : 0;
+ }
+
+ eint->pins[id].enabled = true;
+ eint->pins[id].instance = inst;
+ eint->pins[id].index = idx;
+ eint->pins[id].debounce = support_deb;
+
+ eint->instances[inst].pin_list[idx] = id;
+ eint->instances[inst].number++;
+
+#if defined(MTK_EINT_DEBUG)
+ pin = eint->pins[id];
+ dev_info(eint->dev,
+ "EINT%u in (%u-%u), su_deb = %u",
+ id,
+ pin.instance,
+ eint->instances[inst].number,
+ pin.debounce,
+#endif
+ }
+
+ for (i = 0; i < eint->instance_number; i++) {
+ size = (eint->instances[i].number / MAX_BIT + 1) * sizeof(unsigned int);
+ eint->instances[i].wake_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+ eint->instances[i].cur_mask =
+ devm_kzalloc(eint->dev, size, GFP_KERNEL);
+
+ if (!eint->instances[i].wake_mask ||
+ !eint->instances[i].cur_mask)
+ return -ENOMEM;
+ }
+
+ eint->comp = &default_compat;
+
+ eint->irq = irq_of_parse_and_map(node, 0);
+ if (!eint->irq) {
+ dev_err(eint->dev,
+ "%s IRQ parse fail.\n", __func__);
+ return -EINVAL;
+ }
+
eint->domain = irq_domain_add_linear(eint->dev->of_node,
- eint->hw->ap_num,
+ eint->total_pin_number,
&irq_domain_simple_ops, NULL);
if (!eint->domain)
return -ENOMEM;
- if (eint->hw->db_time) {
- for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
- if (eint->hw->db_time[i] == 0)
- break;
- eint->num_db_time = i;
- }
-
mtk_eint_hw_init(eint);
- for (i = 0; i < eint->hw->ap_num; i++) {
- int virq = irq_create_mapping(eint->domain, i);
+ for (i = 0; i < eint->total_pin_number; i++) {
+ virq = irq_create_mapping(eint->domain, i);
irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
handle_level_irq);
@@ -533,9 +958,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)
irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
eint);
+ global_eintc = eint;
+
return 0;
}
-EXPORT_SYMBOL_GPL(mtk_eint_do_init);
+EXPORT_SYMBOL_GPL(mtk_eint_do_init_v2);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MediaTek EINT Driver");
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 6139b16cd225..aa17a6073029 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -11,6 +11,25 @@
#include <linux/irqdomain.h>
+#define MAX_PIN 999
+#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)
+#define MTK_EINT_NO_OFSET 0
+#define MAX_BIT 32
+#define REG_OFSET 4
+#define REG_GROUP 5
+#define REG_VAL 0xFFFFFFFF
+#define DB_GROUP 8
+#define FIRST 1
+#define SECOND 2
+#define THIRD 3
+#define ARRAY_0 4
+
+//#define MTK_EINT_DEBUG
+
struct mtk_eint_regs {
unsigned int stat;
unsigned int ack;
@@ -30,6 +49,36 @@ struct mtk_eint_regs {
unsigned int dbnc_ctrl;
unsigned int dbnc_set;
unsigned int dbnc_clr;
+ unsigned int event;
+ unsigned int event_set;
+ unsigned int event_clr;
+ unsigned int raw_stat;
+};
+
+struct mtk_eint_ops {
+ void (*ack)(struct irq_data *d);
+};
+
+struct mtk_eint_compatible {
+ struct mtk_eint_ops ops;
+ const struct mtk_eint_regs *regs;
+};
+
+struct mtk_eint_instance {
+ const char *name;
+ void __iomem *base;
+ unsigned int number;
+ unsigned int pin_list[MAX_PIN];
+ unsigned int *wake_mask;
+ unsigned int *cur_mask;
+};
+
+struct mtk_eint_pin {
+ bool enabled;
+ unsigned int instance;
+ unsigned int index;
+ bool debounce;
+ bool dual_edge;
};
struct mtk_eint_hw {
@@ -60,11 +109,14 @@ struct mtk_eint {
struct irq_domain *domain;
int irq;
- int *dual_edge;
- u32 *wake_mask;
- u32 *cur_mask;
-
- /* Used to fit into various EINT device */
+ /* An array to record the coordinate, index by global EINT ID */
+ struct mtk_eint_pin *pins;
+ /* An array to record the global EINT ID, index by coordinate*/
+ struct mtk_eint_instance *instances;
+ unsigned int total_pin_number;
+ unsigned int instance_number;
+ unsigned int dump_target_eint;
+ const struct mtk_eint_compatible *comp;
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
u16 num_db_time;
@@ -74,13 +126,15 @@ struct mtk_eint {
const struct mtk_eint_xt *gpio_xlate;
};
-#if IS_ENABLED(CONFIG_EINT_MTK)
+#if (IS_ENABLED(CONFIG_EINT_MTK) || IS_ENABLED(CONFIG_DEVICE_MODULES_EINT_MTK))
int mtk_eint_do_init(struct mtk_eint *eint);
+int mtk_eint_do_init_v2(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);
+int dump_eint_pin_status(unsigned int eint_num);
#else
static inline int mtk_eint_do_init(struct mtk_eint *eint)
@@ -88,6 +142,11 @@ static inline int mtk_eint_do_init(struct mtk_eint *eint)
return -EOPNOTSUPP;
}
+static inline int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
@@ -108,5 +167,9 @@ static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
return -EOPNOTSUPP;
}
+static inline int dump_eint_pin_status(unsigned int eint_num)
+{
+ return -EOPNOTSUPP;
+}
#endif
#endif /* __MTK_EINT_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index 54301fbba524..a368ef0a3d1e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -367,7 +367,6 @@ static const struct mtk_eint_xt mtk_eint_xt = {
int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- int ret;
if (!IS_ENABLED(CONFIG_EINT_MTK))
return 0;
@@ -379,34 +378,11 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
if (!hw->eint)
return -ENOMEM;
- hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
- if (IS_ERR(hw->eint->base)) {
- ret = PTR_ERR(hw->eint->base);
- goto err_free_eint;
- }
-
- hw->eint->irq = irq_of_parse_and_map(np, 0);
- if (!hw->eint->irq) {
- ret = -EINVAL;
- goto err_free_eint;
- }
-
- if (!hw->soc->eint_hw) {
- ret = -ENODEV;
- goto err_free_eint;
- }
-
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);
-
-err_free_eint:
- devm_kfree(hw->dev, hw->eint);
- hw->eint = NULL;
- return ret;
+ return mtk_eint_do_init_v2(hw->eint);
}
EXPORT_SYMBOL_GPL(mtk_build_eint);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-01-07 11:56 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-25 3:16 [PATCH] pinctrl: mediatek: add eint new design for mt8196 chang hao
2024-10-25 4:12 ` Chen-Yu Tsai
2024-10-26 18:27 ` kernel test robot
2024-10-27 3:35 ` kernel test robot
2024-10-27 18:20 ` kernel test robot
-- strict thread matches above, loose matches on Subject: below --
2024-12-02 8:50 chang hao
2024-12-02 11:50 ` kernel test robot
2024-12-02 12:41 ` kernel test robot
2024-10-25 2:43 chang hao
2024-10-24 14:15 chang hao
2024-10-24 15:55 ` AngeloGioacchino Del Regno
[not found] ` <2d385d533e8f0f23cedad22d4ef46ed4f6550f31.camel@mediatek.com>
2025-01-07 11:36 ` AngeloGioacchino Del Regno
2024-10-24 12:21 chang hao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).