summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/mediatek
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/mediatek')
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c101
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.h4
3 files changed, 99 insertions, 7 deletions
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index d0c811d5f..ad271840d 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -385,6 +385,7 @@ static struct platform_driver mtk_pinctrl_driver = {
.driver = {
.name = "mediatek-mt8173-pinctrl",
.of_match_table = mt8173_pctrl_match,
+ .pm = &mtk_eint_pm_ops,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 4a52072d1..1b22f96ba 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -33,6 +33,7 @@
#include <linux/mfd/syscon.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/pm.h>
#include <dt-bindings/pinctrl/mt65xx.h>
#include "../core.h"
@@ -702,7 +703,7 @@ static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev,
ret = mtk_pctrl_is_function_valid(pctl, g->pin, function);
if (!ret) {
- dev_err(pctl->dev, "invaild function %d on group %d .\n",
+ dev_err(pctl->dev, "invalid function %d on group %d .\n",
function, group);
return -EINVAL;
}
@@ -1062,6 +1063,77 @@ static int mtk_eint_set_type(struct irq_data *d,
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;
+}
+
+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;
+}
+
+const struct dev_pm_ops mtk_eint_pm_ops = {
+ .suspend = mtk_eint_suspend,
+ .resume = mtk_eint_resume,
+};
+
static void mtk_eint_ack(struct irq_data *d)
{
struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
@@ -1076,10 +1148,12 @@ static void mtk_eint_ack(struct irq_data *d)
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,
};
@@ -1116,10 +1190,10 @@ mtk_eint_debounce_process(struct mtk_pinctrl *pctl, int index)
}
}
-static void mtk_eint_irq_handler(unsigned irq, struct irq_desc *desc)
+static void mtk_eint_irq_handler(struct irq_desc *desc)
{
- struct irq_chip *chip = irq_get_chip(irq);
- struct mtk_pinctrl *pctl = irq_get_handler_data(irq);
+ 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 =
@@ -1211,7 +1285,7 @@ int mtk_pctrl_init(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node, *node;
struct property *prop;
struct resource *res;
- int i, ret, irq;
+ int i, ret, irq, ports_buf;
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
if (!pctl)
@@ -1318,6 +1392,21 @@ int mtk_pctrl_init(struct platform_device *pdev,
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) {
@@ -1347,11 +1436,9 @@ int mtk_pctrl_init(struct platform_device *pdev,
irq_set_chip_and_handler(virq, &mtk_pinctrl_irq_chip,
handle_level_irq);
irq_set_chip_data(virq, pctl);
- set_irq_flags(virq, IRQF_VALID);
};
irq_set_chained_handler_and_data(irq, mtk_eint_irq_handler, pctl);
- set_irq_flags(irq, IRQF_VALID);
return 0;
chip_error:
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
index c532c23c7..55a534338 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -267,6 +267,8 @@ struct mtk_pinctrl {
void __iomem *eint_reg_base;
struct irq_domain *domain;
int *eint_dual_edges;
+ u32 *wake_mask;
+ u32 *cur_mask;
};
int mtk_pctrl_init(struct platform_device *pdev,
@@ -282,4 +284,6 @@ int mtk_pconf_spec_set_ies_smt_range(struct regmap *regmap,
const struct mtk_pin_ies_smt_set *ies_smt_infos, unsigned int info_num,
unsigned int pin, unsigned char align, int value);
+extern const struct dev_pm_ops mtk_eint_pm_ops;
+
#endif /* __PINCTRL_MTK_COMMON_H */