Message ID | 20241025031814.21442-1-ot_chhao.chang@mediatek.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | pinctrl: mediatek: add eint new design for mt8196 | expand |
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 > >
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
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
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
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);