Skip to content

Commit 0b65118

Browse files
David Collinsdtor
authored andcommitted
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: David Collins <collinsd@codeaurora.org> Signed-off-by: Anjelique Melendez <quic_amelende@quicinc.com> Link: https://lore.kernel.org/r/20220422191239.6271-5-quic_amelende@quicinc.com Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
1 parent 8ac8904 commit 0b65118

1 file changed

Lines changed: 77 additions & 6 deletions

File tree

drivers/input/misc/pm8941-pwrkey.c

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/input.h>
1010
#include <linux/interrupt.h>
1111
#include <linux/kernel.h>
12+
#include <linux/ktime.h>
1213
#include <linux/log2.h>
1314
#include <linux/module.h>
1415
#include <linux/of.h>
@@ -20,6 +21,16 @@
2021

2122
#define PON_REV2 0x01
2223

24+
#define PON_SUBTYPE 0x05
25+
26+
#define PON_SUBTYPE_PRIMARY 0x01
27+
#define PON_SUBTYPE_SECONDARY 0x02
28+
#define PON_SUBTYPE_1REG 0x03
29+
#define PON_SUBTYPE_GEN2_PRIMARY 0x04
30+
#define PON_SUBTYPE_GEN2_SECONDARY 0x05
31+
#define PON_SUBTYPE_GEN3_PBS 0x08
32+
#define PON_SUBTYPE_GEN3_HLOS 0x09
33+
2334
#define PON_RT_STS 0x10
2435
#define PON_KPDPWR_N_SET BIT(0)
2536
#define PON_RESIN_N_SET BIT(1)
@@ -60,9 +71,12 @@ struct pm8941_pwrkey {
6071
struct input_dev *input;
6172

6273
unsigned int revision;
74+
unsigned int subtype;
6375
struct notifier_block reboot_notifier;
6476

6577
u32 code;
78+
u32 sw_debounce_time_us;
79+
ktime_t sw_debounce_end_time;
6680
const struct pm8941_data *data;
6781
};
6882

@@ -132,20 +146,66 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
132146
{
133147
struct pm8941_pwrkey *pwrkey = _data;
134148
unsigned int sts;
135-
int error;
149+
int err;
150+
151+
if (pwrkey->sw_debounce_time_us) {
152+
if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) {
153+
dev_dbg(pwrkey->dev,
154+
"ignoring key event received before debounce end %llu us\n",
155+
pwrkey->sw_debounce_end_time);
156+
return IRQ_HANDLED;
157+
}
158+
}
136159

137-
error = regmap_read(pwrkey->regmap,
138-
pwrkey->baseaddr + PON_RT_STS, &sts);
139-
if (error)
160+
err = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_RT_STS, &sts);
161+
if (err)
140162
return IRQ_HANDLED;
141163

142-
input_report_key(pwrkey->input, pwrkey->code,
143-
sts & pwrkey->data->status_bit);
164+
sts &= pwrkey->data->status_bit;
165+
166+
if (pwrkey->sw_debounce_time_us && !sts)
167+
pwrkey->sw_debounce_end_time = ktime_add_us(ktime_get(),
168+
pwrkey->sw_debounce_time_us);
169+
170+
input_report_key(pwrkey->input, pwrkey->code, sts);
144171
input_sync(pwrkey->input);
145172

146173
return IRQ_HANDLED;
147174
}
148175

176+
static int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey)
177+
{
178+
unsigned int val, addr, mask;
179+
int error;
180+
181+
if (pwrkey->data->has_pon_pbs && !pwrkey->pon_pbs_baseaddr) {
182+
dev_err(pwrkey->dev,
183+
"PON_PBS address missing, can't read HW debounce time\n");
184+
return 0;
185+
}
186+
187+
if (pwrkey->pon_pbs_baseaddr)
188+
addr = pwrkey->pon_pbs_baseaddr + PON_DBC_CTL;
189+
else
190+
addr = pwrkey->baseaddr + PON_DBC_CTL;
191+
error = regmap_read(pwrkey->regmap, addr, &val);
192+
if (error)
193+
return error;
194+
195+
if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY)
196+
mask = 0xf;
197+
else
198+
mask = 0x7;
199+
200+
pwrkey->sw_debounce_time_us =
201+
2 * USEC_PER_SEC / (1 << (mask - (val & mask)));
202+
203+
dev_dbg(pwrkey->dev, "SW debounce time = %u us\n",
204+
pwrkey->sw_debounce_time_us);
205+
206+
return 0;
207+
}
208+
149209
static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
150210
{
151211
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -238,6 +298,13 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
238298
return error;
239299
}
240300

301+
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_SUBTYPE,
302+
&pwrkey->subtype);
303+
if (error) {
304+
dev_err(&pdev->dev, "failed to read subtype: %d\n", error);
305+
return error;
306+
}
307+
241308
error = of_property_read_u32(pdev->dev.of_node, "linux,code",
242309
&pwrkey->code);
243310
if (error) {
@@ -272,6 +339,10 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
272339
}
273340
}
274341

342+
error = pm8941_pwrkey_sw_debounce_init(pwrkey);
343+
if (error)
344+
return error;
345+
275346
if (pwrkey->data->pull_up_bit) {
276347
error = regmap_update_bits(pwrkey->regmap,
277348
pwrkey->baseaddr + PON_PULL_CTL,

0 commit comments

Comments
 (0)