|
@@ -38,6 +38,7 @@
|
|
|
#include "../core.h"
|
|
|
#include "../pinconf.h"
|
|
|
#include "../pinctrl-utils.h"
|
|
|
+#include "mtk-eint.h"
|
|
|
#include "pinctrl-mtk-common.h"
|
|
|
|
|
|
#define MAX_GPIO_MODE_PER_REG 5
|
|
@@ -831,243 +832,38 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
|
|
|
|
static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
|
{
|
|
|
- const struct mtk_desc_pin *pin;
|
|
|
struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
|
|
|
- int irq;
|
|
|
-
|
|
|
- pin = pctl->devdata->pins + offset;
|
|
|
- if (pin->eint.eintnum == NO_EINT_SUPPORT)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- irq = irq_find_mapping(pctl->domain, pin->eint.eintnum);
|
|
|
- if (!irq)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- return irq;
|
|
|
-}
|
|
|
-
|
|
|
-static int mtk_pinctrl_irq_request_resources(struct irq_data *d)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
- const struct mtk_desc_pin *pin;
|
|
|
- int ret;
|
|
|
-
|
|
|
- pin = mtk_find_pin_by_eint_num(pctl, d->hwirq);
|
|
|
-
|
|
|
- if (!pin) {
|
|
|
- dev_err(pctl->dev, "Can not find pin\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- ret = gpiochip_lock_as_irq(pctl->chip, pin->pin.number);
|
|
|
- if (ret) {
|
|
|
- dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
|
|
|
- irqd_to_hwirq(d));
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- /* set mux to INT mode */
|
|
|
- mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
|
|
|
- /* set gpio direction to input */
|
|
|
- mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number, true);
|
|
|
- /* set input-enable */
|
|
|
- mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1, PIN_CONFIG_INPUT_ENABLE);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void mtk_pinctrl_irq_release_resources(struct irq_data *d)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
- const struct mtk_desc_pin *pin;
|
|
|
-
|
|
|
- pin = mtk_find_pin_by_eint_num(pctl, d->hwirq);
|
|
|
-
|
|
|
- if (!pin) {
|
|
|
- dev_err(pctl->dev, "Can not find pin\n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- gpiochip_unlock_as_irq(pctl->chip, pin->pin.number);
|
|
|
-}
|
|
|
-
|
|
|
-static void __iomem *mtk_eint_get_offset(struct mtk_pinctrl *pctl,
|
|
|
- unsigned int eint_num, unsigned int offset)
|
|
|
-{
|
|
|
- unsigned int eint_base = 0;
|
|
|
- void __iomem *reg;
|
|
|
-
|
|
|
- if (eint_num >= pctl->devdata->ap_num)
|
|
|
- eint_base = pctl->devdata->ap_num;
|
|
|
-
|
|
|
- reg = pctl->eint_reg_base + offset + ((eint_num - eint_base) / 32) * 4;
|
|
|
-
|
|
|
- return reg;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * mtk_can_en_debounce: Check the EINT number is able to enable debounce or not
|
|
|
- * @eint_num: the EINT number to setmtk_pinctrl
|
|
|
- */
|
|
|
-static unsigned int mtk_eint_can_en_debounce(struct mtk_pinctrl *pctl,
|
|
|
- unsigned int eint_num)
|
|
|
-{
|
|
|
- unsigned int sens;
|
|
|
- unsigned int bit = BIT(eint_num % 32);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
-
|
|
|
- void __iomem *reg = mtk_eint_get_offset(pctl, eint_num,
|
|
|
- eint_offsets->sens);
|
|
|
-
|
|
|
- if (readl(reg) & bit)
|
|
|
- sens = MT_LEVEL_SENSITIVE;
|
|
|
- else
|
|
|
- sens = MT_EDGE_SENSITIVE;
|
|
|
-
|
|
|
- if ((eint_num < pctl->devdata->db_cnt) && (sens != MT_EDGE_SENSITIVE))
|
|
|
- return 1;
|
|
|
- else
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * mtk_eint_get_mask: To get the eint mask
|
|
|
- * @eint_num: the EINT number to get
|
|
|
- */
|
|
|
-static unsigned int mtk_eint_get_mask(struct mtk_pinctrl *pctl,
|
|
|
- unsigned int eint_num)
|
|
|
-{
|
|
|
- unsigned int bit = BIT(eint_num % 32);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
-
|
|
|
- void __iomem *reg = mtk_eint_get_offset(pctl, eint_num,
|
|
|
- eint_offsets->mask);
|
|
|
-
|
|
|
- return !!(readl(reg) & bit);
|
|
|
-}
|
|
|
-
|
|
|
-static int mtk_eint_flip_edge(struct mtk_pinctrl *pctl, int hwirq)
|
|
|
-{
|
|
|
- int start_level, curr_level;
|
|
|
- unsigned int reg_offset;
|
|
|
- const struct mtk_eint_offsets *eint_offsets = &(pctl->devdata->eint_offsets);
|
|
|
- u32 mask = BIT(hwirq & 0x1f);
|
|
|
- u32 port = (hwirq >> 5) & eint_offsets->port_mask;
|
|
|
- void __iomem *reg = pctl->eint_reg_base + (port << 2);
|
|
|
- const struct mtk_desc_pin *pin;
|
|
|
-
|
|
|
- pin = mtk_find_pin_by_eint_num(pctl, hwirq);
|
|
|
- curr_level = mtk_gpio_get(pctl->chip, pin->pin.number);
|
|
|
- do {
|
|
|
- start_level = curr_level;
|
|
|
- if (start_level)
|
|
|
- reg_offset = eint_offsets->pol_clr;
|
|
|
- else
|
|
|
- reg_offset = eint_offsets->pol_set;
|
|
|
- writel(mask, reg + reg_offset);
|
|
|
-
|
|
|
- curr_level = mtk_gpio_get(pctl->chip, pin->pin.number);
|
|
|
- } while (start_level != curr_level);
|
|
|
-
|
|
|
- return start_level;
|
|
|
-}
|
|
|
-
|
|
|
-static void mtk_eint_mask(struct irq_data *d)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
- u32 mask = BIT(d->hwirq & 0x1f);
|
|
|
- void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
|
|
|
- eint_offsets->mask_set);
|
|
|
-
|
|
|
- writel(mask, reg);
|
|
|
-}
|
|
|
-
|
|
|
-static void mtk_eint_unmask(struct irq_data *d)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
- u32 mask = BIT(d->hwirq & 0x1f);
|
|
|
- void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
|
|
|
- eint_offsets->mask_clr);
|
|
|
-
|
|
|
- writel(mask, reg);
|
|
|
-
|
|
|
- if (pctl->eint_dual_edges[d->hwirq])
|
|
|
- mtk_eint_flip_edge(pctl, d->hwirq);
|
|
|
-}
|
|
|
-
|
|
|
-static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
|
|
|
- unsigned debounce)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = dev_get_drvdata(chip->parent);
|
|
|
- int eint_num, virq, eint_offset;
|
|
|
- unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
|
|
|
- static const unsigned int debounce_time[] = {500, 1000, 16000, 32000, 64000,
|
|
|
- 128000, 256000};
|
|
|
const struct mtk_desc_pin *pin;
|
|
|
- struct irq_data *d;
|
|
|
+ unsigned long eint_n;
|
|
|
|
|
|
pin = pctl->devdata->pins + offset;
|
|
|
if (pin->eint.eintnum == NO_EINT_SUPPORT)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- eint_num = pin->eint.eintnum;
|
|
|
- virq = irq_find_mapping(pctl->domain, eint_num);
|
|
|
- eint_offset = (eint_num % 4) * 8;
|
|
|
- d = irq_get_irq_data(virq);
|
|
|
-
|
|
|
- set_offset = (eint_num / 4) * 4 + pctl->devdata->eint_offsets.dbnc_set;
|
|
|
- clr_offset = (eint_num / 4) * 4 + pctl->devdata->eint_offsets.dbnc_clr;
|
|
|
- if (!mtk_eint_can_en_debounce(pctl, eint_num))
|
|
|
- return -ENOSYS;
|
|
|
-
|
|
|
- dbnc = ARRAY_SIZE(debounce_time);
|
|
|
- for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
|
|
|
- if (debounce <= debounce_time[i]) {
|
|
|
- dbnc = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ eint_n = pin->eint.eintnum;
|
|
|
|
|
|
- if (!mtk_eint_get_mask(pctl, eint_num)) {
|
|
|
- mtk_eint_mask(d);
|
|
|
- unmask = 1;
|
|
|
- } else {
|
|
|
- unmask = 0;
|
|
|
- }
|
|
|
-
|
|
|
- clr_bit = 0xff << eint_offset;
|
|
|
- writel(clr_bit, pctl->eint_reg_base + clr_offset);
|
|
|
-
|
|
|
- bit = ((dbnc << EINT_DBNC_SET_DBNC_BITS) | EINT_DBNC_SET_EN) <<
|
|
|
- eint_offset;
|
|
|
- rst = EINT_DBNC_RST_BIT << eint_offset;
|
|
|
- writel(rst | bit, pctl->eint_reg_base + set_offset);
|
|
|
-
|
|
|
- /* Delay a while (more than 2T) to wait for hw debounce counter reset
|
|
|
- work correctly */
|
|
|
- udelay(1);
|
|
|
- if (unmask == 1)
|
|
|
- mtk_eint_unmask(d);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return mtk_eint_find_irq(pctl->eint, eint_n);
|
|
|
}
|
|
|
|
|
|
static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned offset,
|
|
|
unsigned long config)
|
|
|
{
|
|
|
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
|
|
|
+ const struct mtk_desc_pin *pin;
|
|
|
+ unsigned long eint_n;
|
|
|
u32 debounce;
|
|
|
|
|
|
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
|
|
|
return -ENOTSUPP;
|
|
|
|
|
|
+ pin = pctl->devdata->pins + offset;
|
|
|
+ if (pin->eint.eintnum == NO_EINT_SUPPORT)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
debounce = pinconf_to_config_argument(config);
|
|
|
- return mtk_gpio_set_debounce(chip, offset, debounce);
|
|
|
+ eint_n = pin->eint.eintnum;
|
|
|
+
|
|
|
+ return mtk_eint_set_debounce(pctl->eint, eint_n, debounce);
|
|
|
}
|
|
|
|
|
|
static const struct gpio_chip mtk_gpio_chip = {
|
|
@@ -1084,117 +880,18 @@ static const struct gpio_chip mtk_gpio_chip = {
|
|
|
.of_gpio_n_cells = 2,
|
|
|
};
|
|
|
|
|
|
-static int mtk_eint_set_type(struct irq_data *d,
|
|
|
- unsigned int type)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
- u32 mask = BIT(d->hwirq & 0x1f);
|
|
|
- void __iomem *reg;
|
|
|
-
|
|
|
- if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
|
|
|
- ((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) {
|
|
|
- dev_err(pctl->dev, "Can't configure IRQ%d (EINT%lu) for type 0x%X\n",
|
|
|
- d->irq, d->hwirq, type);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
|
|
|
- pctl->eint_dual_edges[d->hwirq] = 1;
|
|
|
- else
|
|
|
- pctl->eint_dual_edges[d->hwirq] = 0;
|
|
|
-
|
|
|
- if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
|
|
|
- reg = mtk_eint_get_offset(pctl, d->hwirq,
|
|
|
- eint_offsets->pol_clr);
|
|
|
- writel(mask, reg);
|
|
|
- } else {
|
|
|
- reg = mtk_eint_get_offset(pctl, d->hwirq,
|
|
|
- eint_offsets->pol_set);
|
|
|
- writel(mask, reg);
|
|
|
- }
|
|
|
-
|
|
|
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
|
|
|
- reg = mtk_eint_get_offset(pctl, d->hwirq,
|
|
|
- eint_offsets->sens_clr);
|
|
|
- writel(mask, reg);
|
|
|
- } else {
|
|
|
- reg = mtk_eint_get_offset(pctl, d->hwirq,
|
|
|
- eint_offsets->sens_set);
|
|
|
- writel(mask, reg);
|
|
|
- }
|
|
|
-
|
|
|
- if (pctl->eint_dual_edges[d->hwirq])
|
|
|
- mtk_eint_flip_edge(pctl, d->hwirq);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
- int shift = d->hwirq & 0x1f;
|
|
|
- int reg = d->hwirq >> 5;
|
|
|
-
|
|
|
- if (on)
|
|
|
- pctl->wake_mask[reg] |= BIT(shift);
|
|
|
- else
|
|
|
- pctl->wake_mask[reg] &= ~BIT(shift);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void mtk_eint_chip_write_mask(const struct mtk_eint_offsets *chip,
|
|
|
- void __iomem *eint_reg_base, u32 *buf)
|
|
|
-{
|
|
|
- int port;
|
|
|
- void __iomem *reg;
|
|
|
-
|
|
|
- for (port = 0; port < chip->ports; port++) {
|
|
|
- reg = eint_reg_base + (port << 2);
|
|
|
- writel_relaxed(~buf[port], reg + chip->mask_set);
|
|
|
- writel_relaxed(buf[port], reg + chip->mask_clr);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void mtk_eint_chip_read_mask(const struct mtk_eint_offsets *chip,
|
|
|
- void __iomem *eint_reg_base, u32 *buf)
|
|
|
-{
|
|
|
- int port;
|
|
|
- void __iomem *reg;
|
|
|
-
|
|
|
- for (port = 0; port < chip->ports; port++) {
|
|
|
- reg = eint_reg_base + chip->mask + (port << 2);
|
|
|
- buf[port] = ~readl_relaxed(reg);
|
|
|
- /* Mask is 0 when irq is enabled, and 1 when disabled. */
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static int mtk_eint_suspend(struct device *device)
|
|
|
{
|
|
|
- void __iomem *reg;
|
|
|
struct mtk_pinctrl *pctl = dev_get_drvdata(device);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
|
|
|
- reg = pctl->eint_reg_base;
|
|
|
- mtk_eint_chip_read_mask(eint_offsets, reg, pctl->cur_mask);
|
|
|
- mtk_eint_chip_write_mask(eint_offsets, reg, pctl->wake_mask);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return mtk_eint_do_suspend(pctl->eint);
|
|
|
}
|
|
|
|
|
|
static int mtk_eint_resume(struct device *device)
|
|
|
{
|
|
|
struct mtk_pinctrl *pctl = dev_get_drvdata(device);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
|
|
|
- mtk_eint_chip_write_mask(eint_offsets,
|
|
|
- pctl->eint_reg_base, pctl->cur_mask);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return mtk_eint_do_resume(pctl->eint);
|
|
|
}
|
|
|
|
|
|
const struct dev_pm_ops mtk_eint_pm_ops = {
|
|
@@ -1202,117 +899,6 @@ const struct dev_pm_ops mtk_eint_pm_ops = {
|
|
|
.resume_noirq = mtk_eint_resume,
|
|
|
};
|
|
|
|
|
|
-static void mtk_eint_ack(struct irq_data *d)
|
|
|
-{
|
|
|
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
- u32 mask = BIT(d->hwirq & 0x1f);
|
|
|
- void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
|
|
|
- eint_offsets->ack);
|
|
|
-
|
|
|
- writel(mask, reg);
|
|
|
-}
|
|
|
-
|
|
|
-static struct irq_chip mtk_pinctrl_irq_chip = {
|
|
|
- .name = "mt-eint",
|
|
|
- .irq_disable = mtk_eint_mask,
|
|
|
- .irq_mask = mtk_eint_mask,
|
|
|
- .irq_unmask = mtk_eint_unmask,
|
|
|
- .irq_ack = mtk_eint_ack,
|
|
|
- .irq_set_type = mtk_eint_set_type,
|
|
|
- .irq_set_wake = mtk_eint_irq_set_wake,
|
|
|
- .irq_request_resources = mtk_pinctrl_irq_request_resources,
|
|
|
- .irq_release_resources = mtk_pinctrl_irq_release_resources,
|
|
|
-};
|
|
|
-
|
|
|
-static unsigned int mtk_eint_init(struct mtk_pinctrl *pctl)
|
|
|
-{
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
- void __iomem *reg = pctl->eint_reg_base + eint_offsets->dom_en;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- for (i = 0; i < pctl->devdata->ap_num; i += 32) {
|
|
|
- writel(0xffffffff, reg);
|
|
|
- reg += 4;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static inline void
|
|
|
-mtk_eint_debounce_process(struct mtk_pinctrl *pctl, int index)
|
|
|
-{
|
|
|
- unsigned int rst, ctrl_offset;
|
|
|
- unsigned int bit, dbnc;
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
-
|
|
|
- ctrl_offset = (index / 4) * 4 + eint_offsets->dbnc_ctrl;
|
|
|
- dbnc = readl(pctl->eint_reg_base + ctrl_offset);
|
|
|
- bit = EINT_DBNC_SET_EN << ((index % 4) * 8);
|
|
|
- if ((bit & dbnc) > 0) {
|
|
|
- ctrl_offset = (index / 4) * 4 + eint_offsets->dbnc_set;
|
|
|
- rst = EINT_DBNC_RST_BIT << ((index % 4) * 8);
|
|
|
- writel(rst, pctl->eint_reg_base + ctrl_offset);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void mtk_eint_irq_handler(struct irq_desc *desc)
|
|
|
-{
|
|
|
- struct irq_chip *chip = irq_desc_get_chip(desc);
|
|
|
- struct mtk_pinctrl *pctl = irq_desc_get_handler_data(desc);
|
|
|
- unsigned int status, eint_num;
|
|
|
- int offset, index, virq;
|
|
|
- const struct mtk_eint_offsets *eint_offsets =
|
|
|
- &pctl->devdata->eint_offsets;
|
|
|
- void __iomem *reg = mtk_eint_get_offset(pctl, 0, eint_offsets->stat);
|
|
|
- int dual_edges, start_level, curr_level;
|
|
|
- const struct mtk_desc_pin *pin;
|
|
|
-
|
|
|
- chained_irq_enter(chip, desc);
|
|
|
- for (eint_num = 0;
|
|
|
- eint_num < pctl->devdata->ap_num;
|
|
|
- eint_num += 32, reg += 4) {
|
|
|
- status = readl(reg);
|
|
|
- while (status) {
|
|
|
- offset = __ffs(status);
|
|
|
- index = eint_num + offset;
|
|
|
- virq = irq_find_mapping(pctl->domain, index);
|
|
|
- status &= ~BIT(offset);
|
|
|
-
|
|
|
- dual_edges = pctl->eint_dual_edges[index];
|
|
|
- if (dual_edges) {
|
|
|
- /* Clear soft-irq in case we raised it
|
|
|
- last time */
|
|
|
- writel(BIT(offset), reg - eint_offsets->stat +
|
|
|
- eint_offsets->soft_clr);
|
|
|
-
|
|
|
- pin = mtk_find_pin_by_eint_num(pctl, index);
|
|
|
- start_level = mtk_gpio_get(pctl->chip,
|
|
|
- pin->pin.number);
|
|
|
- }
|
|
|
-
|
|
|
- generic_handle_irq(virq);
|
|
|
-
|
|
|
- if (dual_edges) {
|
|
|
- curr_level = mtk_eint_flip_edge(pctl, index);
|
|
|
-
|
|
|
- /* If level changed, we might lost one edge
|
|
|
- interrupt, raised it through soft-irq */
|
|
|
- if (start_level != curr_level)
|
|
|
- writel(BIT(offset), reg -
|
|
|
- eint_offsets->stat +
|
|
|
- eint_offsets->soft_set);
|
|
|
- }
|
|
|
-
|
|
|
- if (index < pctl->devdata->db_cnt)
|
|
|
- mtk_eint_debounce_process(pctl , index);
|
|
|
- }
|
|
|
- }
|
|
|
- chained_irq_exit(chip, desc);
|
|
|
-}
|
|
|
-
|
|
|
static int mtk_pctrl_build_state(struct platform_device *pdev)
|
|
|
{
|
|
|
struct mtk_pinctrl *pctl = platform_get_drvdata(pdev);
|
|
@@ -1345,6 +931,97 @@ static int mtk_pctrl_build_state(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+mtk_xt_get_gpio_n(void *data, unsigned long eint_n, unsigned int *gpio_n,
|
|
|
+ struct gpio_chip **gpio_chip)
|
|
|
+{
|
|
|
+ struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
|
|
|
+ const struct mtk_desc_pin *pin;
|
|
|
+
|
|
|
+ pin = mtk_find_pin_by_eint_num(pctl, eint_n);
|
|
|
+ if (!pin)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ *gpio_chip = pctl->chip;
|
|
|
+ *gpio_n = pin->pin.number;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
|
|
|
+{
|
|
|
+ struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
|
|
|
+ const struct mtk_desc_pin *pin;
|
|
|
+
|
|
|
+ pin = mtk_find_pin_by_eint_num(pctl, eint_n);
|
|
|
+ if (!pin)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return mtk_gpio_get(pctl->chip, pin->pin.number);
|
|
|
+}
|
|
|
+
|
|
|
+static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
|
|
|
+{
|
|
|
+ struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
|
|
|
+ const struct mtk_desc_pin *pin;
|
|
|
+
|
|
|
+ pin = mtk_find_pin_by_eint_num(pctl, eint_n);
|
|
|
+ if (!pin)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* set mux to INT mode */
|
|
|
+ mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
|
|
|
+ /* set gpio direction to input */
|
|
|
+ mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number,
|
|
|
+ true);
|
|
|
+ /* set input-enable */
|
|
|
+ mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1,
|
|
|
+ PIN_CONFIG_INPUT_ENABLE);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct mtk_eint_xt mtk_eint_xt = {
|
|
|
+ .get_gpio_n = mtk_xt_get_gpio_n,
|
|
|
+ .get_gpio_state = mtk_xt_get_gpio_state,
|
|
|
+ .set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
|
|
|
+};
|
|
|
+
|
|
|
+static int mtk_eint_init(struct mtk_pinctrl *pctl, struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
|
+ struct resource *res;
|
|
|
+
|
|
|
+ if (!of_property_read_bool(np, "interrupt-controller"))
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ pctl->eint = devm_kzalloc(pctl->dev, sizeof(*pctl->eint), GFP_KERNEL);
|
|
|
+ if (!pctl->eint)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
+ if (!res) {
|
|
|
+ dev_err(&pdev->dev, "Unable to get eint resource\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ pctl->eint->base = devm_ioremap_resource(&pdev->dev, res);
|
|
|
+ if (IS_ERR(pctl->eint->base))
|
|
|
+ return PTR_ERR(pctl->eint->base);
|
|
|
+
|
|
|
+ pctl->eint->irq = irq_of_parse_and_map(np, 0);
|
|
|
+ if (!pctl->eint->irq)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pctl->eint->dev = &pdev->dev;
|
|
|
+ pctl->eint->regs = &pctl->devdata->eint_regs;
|
|
|
+ pctl->eint->hw = &pctl->devdata->eint_hw;
|
|
|
+ pctl->eint->pctl = pctl;
|
|
|
+ pctl->eint->gpio_xlate = &mtk_eint_xt;
|
|
|
+
|
|
|
+ return mtk_eint_do_init(pctl->eint);
|
|
|
+}
|
|
|
+
|
|
|
int mtk_pctrl_init(struct platform_device *pdev,
|
|
|
const struct mtk_pinctrl_devdata *data,
|
|
|
struct regmap *regmap)
|
|
@@ -1353,8 +1030,7 @@ int mtk_pctrl_init(struct platform_device *pdev,
|
|
|
struct mtk_pinctrl *pctl;
|
|
|
struct device_node *np = pdev->dev.of_node, *node;
|
|
|
struct property *prop;
|
|
|
- struct resource *res;
|
|
|
- int i, ret, irq, ports_buf;
|
|
|
+ int ret, i;
|
|
|
|
|
|
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
|
|
|
if (!pctl)
|
|
@@ -1441,70 +1117,10 @@ int mtk_pctrl_init(struct platform_device *pdev,
|
|
|
goto chip_error;
|
|
|
}
|
|
|
|
|
|
- if (!of_property_read_bool(np, "interrupt-controller"))
|
|
|
- return 0;
|
|
|
-
|
|
|
- /* Get EINT register base from dts. */
|
|
|
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
- if (!res) {
|
|
|
- dev_err(&pdev->dev, "Unable to get Pinctrl resource\n");
|
|
|
- ret = -EINVAL;
|
|
|
- goto chip_error;
|
|
|
- }
|
|
|
-
|
|
|
- pctl->eint_reg_base = devm_ioremap_resource(&pdev->dev, res);
|
|
|
- if (IS_ERR(pctl->eint_reg_base)) {
|
|
|
- ret = -EINVAL;
|
|
|
- goto chip_error;
|
|
|
- }
|
|
|
-
|
|
|
- ports_buf = pctl->devdata->eint_offsets.ports;
|
|
|
- pctl->wake_mask = devm_kcalloc(&pdev->dev, ports_buf,
|
|
|
- sizeof(*pctl->wake_mask), GFP_KERNEL);
|
|
|
- if (!pctl->wake_mask) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto chip_error;
|
|
|
- }
|
|
|
-
|
|
|
- pctl->cur_mask = devm_kcalloc(&pdev->dev, ports_buf,
|
|
|
- sizeof(*pctl->cur_mask), GFP_KERNEL);
|
|
|
- if (!pctl->cur_mask) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto chip_error;
|
|
|
- }
|
|
|
-
|
|
|
- pctl->eint_dual_edges = devm_kcalloc(&pdev->dev, pctl->devdata->ap_num,
|
|
|
- sizeof(int), GFP_KERNEL);
|
|
|
- if (!pctl->eint_dual_edges) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto chip_error;
|
|
|
- }
|
|
|
-
|
|
|
- irq = irq_of_parse_and_map(np, 0);
|
|
|
- if (!irq) {
|
|
|
- dev_err(&pdev->dev, "couldn't parse and map irq\n");
|
|
|
- ret = -EINVAL;
|
|
|
- goto chip_error;
|
|
|
- }
|
|
|
-
|
|
|
- pctl->domain = irq_domain_add_linear(np,
|
|
|
- pctl->devdata->ap_num, &irq_domain_simple_ops, NULL);
|
|
|
- if (!pctl->domain) {
|
|
|
- dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
|
|
|
- ret = -ENOMEM;
|
|
|
+ ret = mtk_eint_init(pctl, pdev);
|
|
|
+ if (ret)
|
|
|
goto chip_error;
|
|
|
- }
|
|
|
-
|
|
|
- mtk_eint_init(pctl);
|
|
|
- for (i = 0; i < pctl->devdata->ap_num; i++) {
|
|
|
- int virq = irq_create_mapping(pctl->domain, i);
|
|
|
-
|
|
|
- irq_set_chip_and_handler(virq, &mtk_pinctrl_irq_chip,
|
|
|
- handle_level_irq);
|
|
|
- irq_set_chip_data(virq, pctl);
|
|
|
- }
|
|
|
|
|
|
- irq_set_chained_handler_and_data(irq, mtk_eint_irq_handler, pctl);
|
|
|
return 0;
|
|
|
|
|
|
chip_error:
|