Commit 0b65118e authored by David Collins's avatar David Collins Committed by Dmitry Torokhov

Input: pm8941-pwrkey - add software key press debouncing support

On certain PMICs, an unexpected assertion of KPDPWR_DEB (the
positive logic hardware debounced power key signal) may be seen
during the falling edge of KPDPWR_N (i.e. a power key press) when
it occurs close to the rising edge of SLEEP_CLK.  This then
triggers a spurious KPDPWR interrupt.

Handle this issue by adding software debouncing support to ignore
key events that occur within the hardware debounce delay after the
most recent key release event.
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
Signed-off-by: default avatarAnjelique Melendez <quic_amelende@quicinc.com>
Link: https://lore.kernel.org/r/20220422191239.6271-5-quic_amelende@quicinc.comSigned-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 8ac8904b
......@@ -9,6 +9,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/of.h>
......@@ -20,6 +21,16 @@
#define PON_REV2 0x01
#define PON_SUBTYPE 0x05
#define PON_SUBTYPE_PRIMARY 0x01
#define PON_SUBTYPE_SECONDARY 0x02
#define PON_SUBTYPE_1REG 0x03
#define PON_SUBTYPE_GEN2_PRIMARY 0x04
#define PON_SUBTYPE_GEN2_SECONDARY 0x05
#define PON_SUBTYPE_GEN3_PBS 0x08
#define PON_SUBTYPE_GEN3_HLOS 0x09
#define PON_RT_STS 0x10
#define PON_KPDPWR_N_SET BIT(0)
#define PON_RESIN_N_SET BIT(1)
......@@ -60,9 +71,12 @@ struct pm8941_pwrkey {
struct input_dev *input;
unsigned int revision;
unsigned int subtype;
struct notifier_block reboot_notifier;
u32 code;
u32 sw_debounce_time_us;
ktime_t sw_debounce_end_time;
const struct pm8941_data *data;
};
......@@ -132,20 +146,66 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
{
struct pm8941_pwrkey *pwrkey = _data;
unsigned int sts;
int error;
int err;
if (pwrkey->sw_debounce_time_us) {
if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) {
dev_dbg(pwrkey->dev,
"ignoring key event received before debounce end %llu us\n",
pwrkey->sw_debounce_end_time);
return IRQ_HANDLED;
}
}
error = regmap_read(pwrkey->regmap,
pwrkey->baseaddr + PON_RT_STS, &sts);
if (error)
err = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_RT_STS, &sts);
if (err)
return IRQ_HANDLED;
input_report_key(pwrkey->input, pwrkey->code,
sts & pwrkey->data->status_bit);
sts &= pwrkey->data->status_bit;
if (pwrkey->sw_debounce_time_us && !sts)
pwrkey->sw_debounce_end_time = ktime_add_us(ktime_get(),
pwrkey->sw_debounce_time_us);
input_report_key(pwrkey->input, pwrkey->code, sts);
input_sync(pwrkey->input);
return IRQ_HANDLED;
}
static int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey)
{
unsigned int val, addr, mask;
int error;
if (pwrkey->data->has_pon_pbs && !pwrkey->pon_pbs_baseaddr) {
dev_err(pwrkey->dev,
"PON_PBS address missing, can't read HW debounce time\n");
return 0;
}
if (pwrkey->pon_pbs_baseaddr)
addr = pwrkey->pon_pbs_baseaddr + PON_DBC_CTL;
else
addr = pwrkey->baseaddr + PON_DBC_CTL;
error = regmap_read(pwrkey->regmap, addr, &val);
if (error)
return error;
if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY)
mask = 0xf;
else
mask = 0x7;
pwrkey->sw_debounce_time_us =
2 * USEC_PER_SEC / (1 << (mask - (val & mask)));
dev_dbg(pwrkey->dev, "SW debounce time = %u us\n",
pwrkey->sw_debounce_time_us);
return 0;
}
static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
......@@ -238,6 +298,13 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
return error;
}
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_SUBTYPE,
&pwrkey->subtype);
if (error) {
dev_err(&pdev->dev, "failed to read subtype: %d\n", error);
return error;
}
error = of_property_read_u32(pdev->dev.of_node, "linux,code",
&pwrkey->code);
if (error) {
......@@ -272,6 +339,10 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
}
}
error = pm8941_pwrkey_sw_debounce_init(pwrkey);
if (error)
return error;
if (pwrkey->data->pull_up_bit) {
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + PON_PULL_CTL,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment