aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/keyboard/mtk-pmic-keys.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/keyboard/mtk-pmic-keys.c')
-rw-r--r--drivers/input/keyboard/mtk-pmic-keys.c168
1 files changed, 116 insertions, 52 deletions
diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index 62391d6c7da6..9b34da0ec260 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -9,6 +9,8 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/mt6323/registers.h>
+#include <linux/mfd/mt6331/registers.h>
+#include <linux/mfd/mt6358/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6397/registers.h>
#include <linux/module.h>
@@ -17,17 +19,13 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#define MTK_PMIC_PWRKEY_RST_EN_MASK 0x1
-#define MTK_PMIC_PWRKEY_RST_EN_SHIFT 6
-#define MTK_PMIC_HOMEKEY_RST_EN_MASK 0x1
-#define MTK_PMIC_HOMEKEY_RST_EN_SHIFT 5
-#define MTK_PMIC_RST_DU_MASK 0x3
-#define MTK_PMIC_RST_DU_SHIFT 8
+#define MTK_PMIC_RST_DU_MASK GENMASK(9, 8)
+#define MTK_PMIC_PWRKEY_RST BIT(6)
+#define MTK_PMIC_HOMEKEY_RST BIT(5)
-#define MTK_PMIC_PWRKEY_RST \
- (MTK_PMIC_PWRKEY_RST_EN_MASK << MTK_PMIC_PWRKEY_RST_EN_SHIFT)
-#define MTK_PMIC_HOMEKEY_RST \
- (MTK_PMIC_HOMEKEY_RST_EN_MASK << MTK_PMIC_HOMEKEY_RST_EN_SHIFT)
+#define MTK_PMIC_MT6331_RST_DU_MASK GENMASK(13, 12)
+#define MTK_PMIC_MT6331_PWRKEY_RST BIT(9)
+#define MTK_PMIC_MT6331_HOMEKEY_RST BIT(8)
#define MTK_PMIC_PWRKEY_INDEX 0
#define MTK_PMIC_HOMEKEY_INDEX 1
@@ -38,40 +36,71 @@ struct mtk_pmic_keys_regs {
u32 deb_mask;
u32 intsel_reg;
u32 intsel_mask;
+ u32 rst_en_mask;
};
#define MTK_PMIC_KEYS_REGS(_deb_reg, _deb_mask, \
- _intsel_reg, _intsel_mask) \
+ _intsel_reg, _intsel_mask, _rst_mask) \
{ \
.deb_reg = _deb_reg, \
.deb_mask = _deb_mask, \
.intsel_reg = _intsel_reg, \
.intsel_mask = _intsel_mask, \
+ .rst_en_mask = _rst_mask, \
}
struct mtk_pmic_regs {
const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT];
u32 pmic_rst_reg;
+ u32 rst_lprst_mask; /* Long-press reset timeout bitmask */
};
static const struct mtk_pmic_regs mt6397_regs = {
.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6397_CHRSTATUS,
- 0x8, MT6397_INT_RSV, 0x10),
+ 0x8, MT6397_INT_RSV, 0x10, MTK_PMIC_PWRKEY_RST),
.keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6397_OCSTATUS2,
- 0x10, MT6397_INT_RSV, 0x8),
+ 0x10, MT6397_INT_RSV, 0x8, MTK_PMIC_HOMEKEY_RST),
.pmic_rst_reg = MT6397_TOP_RST_MISC,
+ .rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
};
static const struct mtk_pmic_regs mt6323_regs = {
.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS,
- 0x2, MT6323_INT_MISC_CON, 0x10),
+ 0x2, MT6323_INT_MISC_CON, 0x10, MTK_PMIC_PWRKEY_RST),
.keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS,
- 0x4, MT6323_INT_MISC_CON, 0x8),
+ 0x4, MT6323_INT_MISC_CON, 0x8, MTK_PMIC_HOMEKEY_RST),
.pmic_rst_reg = MT6323_TOP_RST_MISC,
+ .rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
+};
+
+static const struct mtk_pmic_regs mt6331_regs = {
+ .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6331_TOPSTATUS, 0x2,
+ MT6331_INT_MISC_CON, 0x4,
+ MTK_PMIC_MT6331_PWRKEY_RST),
+ .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6331_TOPSTATUS, 0x4,
+ MT6331_INT_MISC_CON, 0x2,
+ MTK_PMIC_MT6331_HOMEKEY_RST),
+ .pmic_rst_reg = MT6331_TOP_RST_MISC,
+ .rst_lprst_mask = MTK_PMIC_MT6331_RST_DU_MASK,
+};
+
+static const struct mtk_pmic_regs mt6358_regs = {
+ .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS,
+ 0x2, MT6358_PSC_TOP_INT_CON0, 0x5,
+ MTK_PMIC_PWRKEY_RST),
+ .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS,
+ 0x8, MT6358_PSC_TOP_INT_CON0, 0xa,
+ MTK_PMIC_HOMEKEY_RST),
+ .pmic_rst_reg = MT6358_TOP_RST_MISC,
+ .rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
};
struct mtk_pmic_keys_info {
@@ -79,6 +108,7 @@ struct mtk_pmic_keys_info {
const struct mtk_pmic_keys_regs *regs;
unsigned int keycode;
int irq;
+ int irq_r; /* optional: release irq if different */
bool wakeup:1;
};
@@ -96,53 +126,49 @@ enum mtk_pmic_keys_lp_mode {
};
static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys,
- u32 pmic_rst_reg)
+ const struct mtk_pmic_regs *regs)
{
- int ret;
+ const struct mtk_pmic_keys_regs *kregs_home, *kregs_pwr;
u32 long_press_mode, long_press_debounce;
+ u32 value, mask;
+ int error;
- ret = of_property_read_u32(keys->dev->of_node,
- "power-off-time-sec", &long_press_debounce);
- if (ret)
+ kregs_home = keys->keys[MTK_PMIC_HOMEKEY_INDEX].regs;
+ kregs_pwr = keys->keys[MTK_PMIC_PWRKEY_INDEX].regs;
+
+ error = of_property_read_u32(keys->dev->of_node, "power-off-time-sec",
+ &long_press_debounce);
+ if (error)
long_press_debounce = 0;
- regmap_update_bits(keys->regmap, pmic_rst_reg,
- MTK_PMIC_RST_DU_MASK << MTK_PMIC_RST_DU_SHIFT,
- long_press_debounce << MTK_PMIC_RST_DU_SHIFT);
+ mask = regs->rst_lprst_mask;
+ value = long_press_debounce << (ffs(regs->rst_lprst_mask) - 1);
- ret = of_property_read_u32(keys->dev->of_node,
- "mediatek,long-press-mode", &long_press_mode);
- if (ret)
+ error = of_property_read_u32(keys->dev->of_node,
+ "mediatek,long-press-mode",
+ &long_press_mode);
+ if (error)
long_press_mode = LP_DISABLE;
switch (long_press_mode) {
- case LP_ONEKEY:
- regmap_update_bits(keys->regmap, pmic_rst_reg,
- MTK_PMIC_PWRKEY_RST,
- MTK_PMIC_PWRKEY_RST);
- regmap_update_bits(keys->regmap, pmic_rst_reg,
- MTK_PMIC_HOMEKEY_RST,
- 0);
- break;
case LP_TWOKEY:
- regmap_update_bits(keys->regmap, pmic_rst_reg,
- MTK_PMIC_PWRKEY_RST,
- MTK_PMIC_PWRKEY_RST);
- regmap_update_bits(keys->regmap, pmic_rst_reg,
- MTK_PMIC_HOMEKEY_RST,
- MTK_PMIC_HOMEKEY_RST);
- break;
+ value |= kregs_home->rst_en_mask;
+ fallthrough;
+
+ case LP_ONEKEY:
+ value |= kregs_pwr->rst_en_mask;
+ fallthrough;
+
case LP_DISABLE:
- regmap_update_bits(keys->regmap, pmic_rst_reg,
- MTK_PMIC_PWRKEY_RST,
- 0);
- regmap_update_bits(keys->regmap, pmic_rst_reg,
- MTK_PMIC_HOMEKEY_RST,
- 0);
+ mask |= kregs_home->rst_en_mask;
+ mask |= kregs_pwr->rst_en_mask;
break;
+
default:
break;
}
+
+ regmap_update_bits(keys->regmap, regs->pmic_rst_reg, mask, value);
}
static irqreturn_t mtk_pmic_keys_irq_handler_thread(int irq, void *data)
@@ -188,6 +214,18 @@ static int mtk_pmic_key_setup(struct mtk_pmic_keys *keys,
return ret;
}
+ if (info->irq_r > 0) {
+ ret = devm_request_threaded_irq(keys->dev, info->irq_r, NULL,
+ mtk_pmic_keys_irq_handler_thread,
+ IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+ "mtk-pmic-keys", info);
+ if (ret) {
+ dev_err(keys->dev, "Failed to request IRQ_r: %d: %d\n",
+ info->irq, ret);
+ return ret;
+ }
+ }
+
input_set_capability(keys->input_dev, EV_KEY, info->keycode);
return 0;
@@ -199,8 +237,11 @@ static int __maybe_unused mtk_pmic_keys_suspend(struct device *dev)
int index;
for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) {
- if (keys->keys[index].wakeup)
+ if (keys->keys[index].wakeup) {
enable_irq_wake(keys->keys[index].irq);
+ if (keys->keys[index].irq_r > 0)
+ enable_irq_wake(keys->keys[index].irq_r);
+ }
}
return 0;
@@ -212,8 +253,11 @@ static int __maybe_unused mtk_pmic_keys_resume(struct device *dev)
int index;
for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) {
- if (keys->keys[index].wakeup)
+ if (keys->keys[index].wakeup) {
disable_irq_wake(keys->keys[index].irq);
+ if (keys->keys[index].irq_r > 0)
+ disable_irq_wake(keys->keys[index].irq_r);
+ }
}
return 0;
@@ -230,6 +274,12 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = {
.compatible = "mediatek,mt6323-keys",
.data = &mt6323_regs,
}, {
+ .compatible = "mediatek,mt6331-keys",
+ .data = &mt6331_regs,
+ }, {
+ .compatible = "mediatek,mt6358-keys",
+ .data = &mt6358_regs,
+ }, {
/* sentinel */
}
};
@@ -241,6 +291,8 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
unsigned int keycount;
struct mt6397_chip *pmic_chip = dev_get_drvdata(pdev->dev.parent);
struct device_node *node = pdev->dev.of_node, *child;
+ static const char *const irqnames[] = { "powerkey", "homekey" };
+ static const char *const irqnames_r[] = { "powerkey_r", "homekey_r" };
struct mtk_pmic_keys *keys;
const struct mtk_pmic_regs *mtk_pmic_regs;
struct input_dev *input_dev;
@@ -268,7 +320,8 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
input_dev->id.version = 0x0001;
keycount = of_get_available_child_count(node);
- if (keycount > MTK_PMIC_MAX_KEY_COUNT) {
+ if (keycount > MTK_PMIC_MAX_KEY_COUNT ||
+ keycount > ARRAY_SIZE(irqnames)) {
dev_err(keys->dev, "too many keys defined (%d)\n", keycount);
return -EINVAL;
}
@@ -276,12 +329,23 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
for_each_child_of_node(node, child) {
keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index];
- keys->keys[index].irq = platform_get_irq(pdev, index);
+ keys->keys[index].irq =
+ platform_get_irq_byname(pdev, irqnames[index]);
if (keys->keys[index].irq < 0) {
of_node_put(child);
return keys->keys[index].irq;
}
+ if (of_device_is_compatible(node, "mediatek,mt6358-keys")) {
+ keys->keys[index].irq_r = platform_get_irq_byname(pdev,
+ irqnames_r[index]);
+
+ if (keys->keys[index].irq_r < 0) {
+ of_node_put(child);
+ return keys->keys[index].irq_r;
+ }
+ }
+
error = of_property_read_u32(child,
"linux,keycodes", &keys->keys[index].keycode);
if (error) {
@@ -311,7 +375,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
return error;
}
- mtk_pmic_keys_lp_reset_setup(keys, mtk_pmic_regs->pmic_rst_reg);
+ mtk_pmic_keys_lp_reset_setup(keys, mtk_pmic_regs);
platform_set_drvdata(pdev, keys);