* [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
* [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-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-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
* Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196
[not found] ` <2d385d533e8f0f23cedad22d4ef46ed4f6550f31.camel@mediatek.com>
@ 2025-01-07 11:36 ` AngeloGioacchino Del Regno
0 siblings, 0 replies; 13+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-01-07 11:36 UTC (permalink / raw)
To: Chhao Chang (常浩), matthias.bgg@gmail.com,
sean.wang@kernel.org, linus.walleij@linaro.org
Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
Zhengnan Chen (陈征南),
Chunhui Li (李春辉),
Wenbin Mei (梅文彬), linux-gpio@vger.kernel.org,
Yong Mao (毛勇), linux-arm-kernel@lists.infradead.org,
Hanks Chen (陳彥廷),
Qingliang Li (黎晴亮),
Axe Yang (杨磊)
Il 26/12/24 10:13, Chhao Chang (常浩) ha scritto:
> Hi Angelo,
> Based on your question, the reply is as follows.
>
Please don't top-post.
> I
> Have you tested this change on other MediaTek SoCs?
>>> I tested the change in 8195, and the EINT function was normal.
>
You tested it only on MT8195, yes - MT8195 and MT8188 will not break entirely, but
all of the other currently supported SoCs will break (example: mt8173, mt8183,
mt2701 and others).
> II
>> + static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
>> + 20000, 40000, 80000, 160000, 320000, 640000 };
> Every SoC has its own debounce time, and this will break all currently
> supported MediaTek SoCs.
>>> We will leave the old IC unchanged and use a unique debounce time for the new IC.
Yes, please.
>
> III
>> +EXPORT_SYMBOL_GPL(dump_eint_pin_status);
> Why do you need to export this function?
>>> some other kernel module maybe need dump pin status for debug.
Sure, but that's not the right way.
>
> IV
> eint_pin_status_show
> Controlling pinctrl from userspace? Isn't there a generic facility to do this?
>>> This interface is used when debug, E.G.
> adb shell "cat /sys/bus/platform/drivers/mt8196-pinctrl/eintc_status"
> adb shell "echo X > /sys/bus/platform/drivers/mt8196-pinctrl/eint_pin_status"
> adb shell "cat /sys/bus/platform/drivers/mt8196-pinctrl/eint_pin_status"
> We have use this interface for many smartphone chips, any suggestion for optimize it?
Debug - For anything that is not already shown by the generic debug from the
pinctrl, pinmux, gpiochip APIs:
struct pinctrl_ops -> pin_dbg_show
struct gpio_chip -> dbg_show
struct pinctrl_desc -> custom_conf_items, custom_params
and there's more, just look into the headers.
You don't need this function as everything can be handled in API.
>
> V
>> + global_eintc = eint;
> No global variables please. Makes no sense.
>>> we should get the pointer of struct mtk_eint in eint_pin_status_store/eint_pin_status_show, but struct device_driver can't transfer the pointer directly, is there a better solution?
>
If you use the debugging facilities provided by the API, you won't have this
problem in the first place...!
Also, setting pins from userspace can also be done without custom functions: again,
just look in the headers and read the documentation.
> VI
>> + ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);
> I'm not really sure that you really need this property, as the eint was declared
> inside of the main pinctrl node for the SoC, and I'm mostly sure that you can keep
> doing the same with eintv2.
>>> mediatek,eint This attribute will be defined under the PINCTRL node, E.G.
> pio: pinctrl@10005000<mailto:pinctrl@10005000> {
> compatible = "mediatek,mt8189-pinctrl";
> reg = <0 0x10005000 0 0x1000>;
> gpio-controller;
> #gpio-cells = <2>;
> gpio-ranges = <&pio 0 0 182>;
> interrupt-controller;
> #interrupt-cells = <2>;
>
> mediatek,eint = <&eint>;
>
> };
>
Yeah you don't need that. The eint driver is "internal" to the pinctrl one, so
you can grab that reference inside of the driver code instead.
You're using this to grab drivers handle, it's software - but devicetree describes
the hardware, not the SW.
> VII
>> + ret = of_property_read_u32(node, "mediatek,total-pin-number",
>> + &eint->total_pin_number);
> This is not for devicetree.
> This is a SoC property and must be specified per-SoC as platform data.
>>> We will define this platform data under the EINT node corresponding to IC DTS, E.G.
> eint: apirq@11ce0000<mailto:apirq@11ce0000> {
> compatible = "mediatek,mt8196-eint";
> reg = <0 0x11ce0000 0 0x1000>,
> <0 0x11de0000 0 0x1000>,
> <0 0x11e60000 0 0x1000>,
> <0 0x1c01e000 0 0x1000>,
> <0 0x11f00000 0 0x1000>;
> reg-name = "eint-e", "eint-s", "eint-w", "eint-c",
There's a standard property for this - it's "reg-names".
> interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH 0>;
> mediatek,instance-num = <5>;
> mediatek,total-pin-number = <210>;
> mediatek,pins = <0 0 0 1>,<1 0 1 1>,<2 0 2 1>,<3 0 3 1>;
> };
>
>
> VIII
>> + if (ret)
>> + eint->instance_number = 1;
> Can one SoC have variable instance numbers? I don't think so.
> That goes to platform data.
>>> this check is for legacy single instance eint, maybe no "mediatek,instance-num" in dts; for multi-instance eint, there should "mediatek,instance-num" in dts.
instance_number = count of eint instances in "reg" or in "reg-names"
You don't need a custom property for that - you can just count the number of
instances that you have defined in reg-names, or in reg.
>
>
> IX
>> + for (i = 0; i < eint->instance_number; i++) {
>> + ret = of_property_read_string_index(node, "reg-name", i,
>> + &(eint->instances[i].name));
> That reg-name is not a standard property; besides, you don't need to parse names,
> as you can restrict the order in bindings you can just parse by knowing the
> number of declared register spaces.
>>> yes, it's not standard, we get instance number by "mediatek,instance-num", then parsing instance name by "reg-name" and instance base by "reg" Sequentially.
The standard one is "reg-names", and there is no valid reason to use a custom one
in this case.
Please use standard properties when possible.
> eint: apirq@11ce0000<mailto:apirq@11ce0000> {
> compatible = "mediatek,mt8196-eint";
> reg = <0 0x11ce0000 0 0x1000>,
> <0 0x11de0000 0 0x1000>,
> <0 0x11e60000 0 0x1000>,
> <0 0x1c01e000 0 0x1000>,
> <0 0x11f00000 0 0x1000>;
> reg-name = "eint-e", "eint-s", "eint-w", "eint-c",
> interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH 0>;
> mediatek,instance-num = <5>;
> mediatek,total-pin-number = <210>;
> mediatek,pins = <0 0 0 1>,<1 0 1 1>,<2 0 2 1>,<3 0 3 1>;
> };
>
> X
>> + matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / 4;
> So basically this means that if a SoC has 200 EINT pins, you'll have 200 values
> in devicetree?!
> That's another thing for platform data instead.
>>> Yes, we will define this platform data under the EINT node corresponding to IC DTS, e.g.
Define that as platform data into the driver, not in DT.
> eint: apirq@11ce0000<mailto:apirq@11ce0000> {
> compatible = "mediatek,mt8196-eint";
> reg = <0 0x11ce0000 0 0x1000>,
> <0 0x11de0000 0 0x1000>,
> <0 0x11e60000 0 0x1000>,
> <0 0x1c01e000 0 0x1000>,
> <0 0x11f00000 0 0x1000>;
> reg-name = "eint-e", "eint-s", "eint-w", "eint-c",
> interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH 0>;
> mediatek,instance-num = <5>;
> mediatek,total-pin-number = <210>;
> mediatek,pins = <0 0 0 1>,<1 0 1 1>,<2 0 2 1>,<3 0 3 1>;
> .....More than 200 PINs are omitted here
> };
>
>
> XI
>> + ret = of_property_read_u32_index(node, "mediatek,pins",
>> + offset, &id);
> Same, that's platform data!
>>> Same, We will define this platform data under the EINT node corresponding to IC DTS.
Not in DT. Define in the driver.
>
> XII
>> +#if defined(MTK_EINT_DEBUG)
> No. You either use a dev_dbg() or you just avoid this print.
> Please remove the MTK_EINT_DEBUG definition entirely.
>>> We will remove MTK_EINT_DEBUG
>
>
>> + ret |= driver_create_file(eint->dev->driver,
>> + &driver_attr_eint_pin_status);
> OR'ing return values is never a good idea.
>>> It is used to determine whether the Eint node has related attributes. Is there a better solution?
ret = your_call();
if (ret)
return ret;
ret = another_call();
if (ret)
return ret;
...etc
>
> XIII
> Linus, that's something like the fourth time that he pushes variations of this
> patch which do break all MediaTek SoCs in a way or another, leaving only MT8196
> hopefully-functional.
>>> Current Design supports previous ICs.
Not entirely. At least the debounce_time breaks old SoCs :-)
Regards,
Angelo
>
>
> Best regards,
> Chhao Chang
>
>
>
>
> On Thu, 2024-10-24 at 17:55 +0200, AngeloGioacchino Del Regno wrote:
> Il 24/10/24 16:15, chang hao ha scritto:
> From: Chhao Chang <ot_chhao.chang@mediatek.com<mailto: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<mailto: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
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).