mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
Merge "input: misc: pm8941-pwrkey: add software key press debouncing support"
This commit is contained in:
commit
3059ef6495
|
|
@ -9,9 +9,11 @@
|
|||
#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>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
|
|
@ -19,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)
|
||||
|
|
@ -45,6 +57,8 @@ struct pm8941_data {
|
|||
unsigned int status_bit;
|
||||
bool supports_ps_hold_poff_config;
|
||||
bool supports_debounce_config;
|
||||
bool needs_sw_debounce;
|
||||
bool has_pon_pbs;
|
||||
const char *name;
|
||||
const char *phys;
|
||||
};
|
||||
|
|
@ -53,13 +67,17 @@ struct pm8941_pwrkey {
|
|||
struct device *dev;
|
||||
int irq;
|
||||
u32 baseaddr;
|
||||
u32 pon_pbs_baseaddr;
|
||||
struct regmap *regmap;
|
||||
struct input_dev *input;
|
||||
|
||||
unsigned int revision;
|
||||
unsigned int subtype;
|
||||
struct notifier_block reboot_notifier;
|
||||
|
||||
u32 code;
|
||||
u32 sw_debounce_time_us;
|
||||
ktime_t last_release_time;
|
||||
const struct pm8941_data *data;
|
||||
};
|
||||
|
||||
|
|
@ -130,19 +148,65 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
|
|||
struct pm8941_pwrkey *pwrkey = _data;
|
||||
unsigned int sts;
|
||||
int error;
|
||||
u64 elapsed_us;
|
||||
|
||||
if (pwrkey->sw_debounce_time_us) {
|
||||
elapsed_us = ktime_us_delta(ktime_get(),
|
||||
pwrkey->last_release_time);
|
||||
if (elapsed_us < pwrkey->sw_debounce_time_us) {
|
||||
dev_dbg(pwrkey->dev, "ignoring key event received after %llu us, debounce time=%u us\n",
|
||||
elapsed_us, pwrkey->sw_debounce_time_us);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
error = regmap_read(pwrkey->regmap,
|
||||
pwrkey->baseaddr + PON_RT_STS, &sts);
|
||||
if (error)
|
||||
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->last_release_time = ktime_get();
|
||||
|
||||
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;
|
||||
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)
|
||||
pwrkey->sw_debounce_time_us = 2 * USEC_PER_SEC /
|
||||
(1 << (0xf - (val & 0xf)));
|
||||
else
|
||||
pwrkey->sw_debounce_time_us = 2 * USEC_PER_SEC /
|
||||
(1 << (0x7 - (val & 0x7)));
|
||||
|
||||
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);
|
||||
|
|
@ -171,6 +235,8 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
|||
struct pm8941_pwrkey *pwrkey;
|
||||
bool pull_up;
|
||||
struct device *parent;
|
||||
struct device_node *regmap_node;
|
||||
const __be32 *addr;
|
||||
u32 req_delay;
|
||||
int error;
|
||||
|
||||
|
|
@ -192,8 +258,10 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
|||
pwrkey->data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
parent = pdev->dev.parent;
|
||||
regmap_node = pdev->dev.of_node;
|
||||
pwrkey->regmap = dev_get_regmap(parent, NULL);
|
||||
if (!pwrkey->regmap) {
|
||||
regmap_node = parent->of_node;
|
||||
/*
|
||||
* We failed to get regmap for parent. Let's see if we are
|
||||
* a child of pon node and read regmap and reg from its
|
||||
|
|
@ -204,15 +272,21 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "failed to locate regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
error = of_property_read_u32(parent->of_node,
|
||||
"reg", &pwrkey->baseaddr);
|
||||
} else {
|
||||
error = of_property_read_u32(pdev->dev.of_node, "reg",
|
||||
&pwrkey->baseaddr);
|
||||
}
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
addr = of_get_address(regmap_node, 0, NULL, NULL);
|
||||
if (!addr) {
|
||||
dev_err(&pdev->dev, "reg property missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pwrkey->baseaddr = be32_to_cpu(*addr);
|
||||
|
||||
if (pwrkey->data->has_pon_pbs) {
|
||||
/* PON_PBS base address is optional */
|
||||
addr = of_get_address(regmap_node, 1, NULL, NULL);
|
||||
if (addr)
|
||||
pwrkey->pon_pbs_baseaddr = be32_to_cpu(*addr);
|
||||
}
|
||||
|
||||
pwrkey->irq = platform_get_irq(pdev, 0);
|
||||
if (pwrkey->irq < 0)
|
||||
|
|
@ -221,7 +295,14 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
|||
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2,
|
||||
&pwrkey->revision);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to set debounce: %d\n", error);
|
||||
dev_err(&pdev->dev, "failed to read revision: %d\n", error);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -259,6 +340,12 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (pwrkey->data->needs_sw_debounce) {
|
||||
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,
|
||||
|
|
@ -320,6 +407,8 @@ static const struct pm8941_data pwrkey_data = {
|
|||
.phys = "pm8941_pwrkey/input0",
|
||||
.supports_ps_hold_poff_config = true,
|
||||
.supports_debounce_config = true,
|
||||
.needs_sw_debounce = true,
|
||||
.has_pon_pbs = false,
|
||||
};
|
||||
|
||||
static const struct pm8941_data resin_data = {
|
||||
|
|
@ -329,6 +418,8 @@ static const struct pm8941_data resin_data = {
|
|||
.phys = "pm8941_resin/input0",
|
||||
.supports_ps_hold_poff_config = true,
|
||||
.supports_debounce_config = true,
|
||||
.needs_sw_debounce = true,
|
||||
.has_pon_pbs = false,
|
||||
};
|
||||
|
||||
static const struct pm8941_data pon_gen3_pwrkey_data = {
|
||||
|
|
@ -337,6 +428,8 @@ static const struct pm8941_data pon_gen3_pwrkey_data = {
|
|||
.phys = "pmic_pwrkey/input0",
|
||||
.supports_ps_hold_poff_config = false,
|
||||
.supports_debounce_config = false,
|
||||
.needs_sw_debounce = true,
|
||||
.has_pon_pbs = true,
|
||||
};
|
||||
|
||||
static const struct pm8941_data pon_gen3_resin_data = {
|
||||
|
|
@ -345,6 +438,8 @@ static const struct pm8941_data pon_gen3_resin_data = {
|
|||
.phys = "pmic_resin/input0",
|
||||
.supports_ps_hold_poff_config = false,
|
||||
.supports_debounce_config = false,
|
||||
.needs_sw_debounce = true,
|
||||
.has_pon_pbs = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id pm8941_pwr_key_id_table[] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user