Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Collins and committed by
Dmitry Torokhov
0b65118e 8ac8904b

+77 -6
+77 -6
drivers/input/misc/pm8941-pwrkey.c
··· 9 9 #include <linux/input.h> 10 10 #include <linux/interrupt.h> 11 11 #include <linux/kernel.h> 12 + #include <linux/ktime.h> 12 13 #include <linux/log2.h> 13 14 #include <linux/module.h> 14 15 #include <linux/of.h> ··· 20 19 #include <linux/regmap.h> 21 20 22 21 #define PON_REV2 0x01 22 + 23 + #define PON_SUBTYPE 0x05 24 + 25 + #define PON_SUBTYPE_PRIMARY 0x01 26 + #define PON_SUBTYPE_SECONDARY 0x02 27 + #define PON_SUBTYPE_1REG 0x03 28 + #define PON_SUBTYPE_GEN2_PRIMARY 0x04 29 + #define PON_SUBTYPE_GEN2_SECONDARY 0x05 30 + #define PON_SUBTYPE_GEN3_PBS 0x08 31 + #define PON_SUBTYPE_GEN3_HLOS 0x09 23 32 24 33 #define PON_RT_STS 0x10 25 34 #define PON_KPDPWR_N_SET BIT(0) ··· 71 60 struct input_dev *input; 72 61 73 62 unsigned int revision; 63 + unsigned int subtype; 74 64 struct notifier_block reboot_notifier; 75 65 76 66 u32 code; 67 + u32 sw_debounce_time_us; 68 + ktime_t sw_debounce_end_time; 77 69 const struct pm8941_data *data; 78 70 }; 79 71 ··· 146 132 { 147 133 struct pm8941_pwrkey *pwrkey = _data; 148 134 unsigned int sts; 149 - int error; 135 + int err; 150 136 151 - error = regmap_read(pwrkey->regmap, 152 - pwrkey->baseaddr + PON_RT_STS, &sts); 153 - if (error) 137 + if (pwrkey->sw_debounce_time_us) { 138 + if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) { 139 + dev_dbg(pwrkey->dev, 140 + "ignoring key event received before debounce end %llu us\n", 141 + pwrkey->sw_debounce_end_time); 142 + return IRQ_HANDLED; 143 + } 144 + } 145 + 146 + err = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_RT_STS, &sts); 147 + if (err) 154 148 return IRQ_HANDLED; 155 149 156 - input_report_key(pwrkey->input, pwrkey->code, 157 - sts & pwrkey->data->status_bit); 150 + sts &= pwrkey->data->status_bit; 151 + 152 + if (pwrkey->sw_debounce_time_us && !sts) 153 + pwrkey->sw_debounce_end_time = ktime_add_us(ktime_get(), 154 + pwrkey->sw_debounce_time_us); 155 + 156 + input_report_key(pwrkey->input, pwrkey->code, sts); 158 157 input_sync(pwrkey->input); 159 158 160 159 return IRQ_HANDLED; 160 + } 161 + 162 + static int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey) 163 + { 164 + unsigned int val, addr, mask; 165 + int error; 166 + 167 + if (pwrkey->data->has_pon_pbs && !pwrkey->pon_pbs_baseaddr) { 168 + dev_err(pwrkey->dev, 169 + "PON_PBS address missing, can't read HW debounce time\n"); 170 + return 0; 171 + } 172 + 173 + if (pwrkey->pon_pbs_baseaddr) 174 + addr = pwrkey->pon_pbs_baseaddr + PON_DBC_CTL; 175 + else 176 + addr = pwrkey->baseaddr + PON_DBC_CTL; 177 + error = regmap_read(pwrkey->regmap, addr, &val); 178 + if (error) 179 + return error; 180 + 181 + if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY) 182 + mask = 0xf; 183 + else 184 + mask = 0x7; 185 + 186 + pwrkey->sw_debounce_time_us = 187 + 2 * USEC_PER_SEC / (1 << (mask - (val & mask))); 188 + 189 + dev_dbg(pwrkey->dev, "SW debounce time = %u us\n", 190 + pwrkey->sw_debounce_time_us); 191 + 192 + return 0; 161 193 } 162 194 163 195 static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev) ··· 298 238 return error; 299 239 } 300 240 241 + error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_SUBTYPE, 242 + &pwrkey->subtype); 243 + if (error) { 244 + dev_err(&pdev->dev, "failed to read subtype: %d\n", error); 245 + return error; 246 + } 247 + 301 248 error = of_property_read_u32(pdev->dev.of_node, "linux,code", 302 249 &pwrkey->code); 303 250 if (error) { ··· 338 271 return error; 339 272 } 340 273 } 274 + 275 + error = pm8941_pwrkey_sw_debounce_init(pwrkey); 276 + if (error) 277 + return error; 341 278 342 279 if (pwrkey->data->pull_up_bit) { 343 280 error = regmap_update_bits(pwrkey->regmap,