input: qpnp-power-on: Add debounce for KPDPWR_N rising edge

On certain PMICs, an unexpected assertion on KPDPWR_DBC may
be seen during falling edge of KPDPWR_N when it is closer
to the rising edge of SLEEP_CLK. This triggers spurious
KPDPWR interrupts. Handle this by adding a debounce in SW
when the first KPDPWR_N falling edge is seen.

The debounce logic is enabled by the DT property
'qcom,kpdpwr-sw-debounce'.

CRs-Fixed: 2032520
Change-Id: I7655c13bda47fa6e2983650d7bec21e52aa91c2f
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
This commit is contained in:
Anirudh Ghayal 2017-04-19 15:23:06 +05:30
parent b1980b6bfe
commit dfdb97d8b9
2 changed files with 59 additions and 4 deletions

View file

@ -82,6 +82,8 @@ Optional properties:
- qcom,shutdown-poweroff-type Same description as qcom,warm-reset-poweroff-
type but this applies for the system shutdown
case.
- qcom,kpdpwr-sw-debounce Boolean property to enable the debounce logic
on the KPDPWR_N rising edge.
All the below properties are in the sub-node section (properties of the child

View file

@ -207,7 +207,7 @@ struct qpnp_pon {
int pon_power_off_reason;
int num_pon_reg;
int num_pon_config;
u32 dbc;
u32 dbc_time_us;
u32 uvlo;
int warm_reset_poff_type;
int hard_reset_poff_type;
@ -219,6 +219,8 @@ struct qpnp_pon {
u8 warm_reset_reason2;
bool is_spon;
bool store_hard_reset_reason;
bool kpdpwr_dbc_enable;
ktime_t kpdpwr_last_release_time;
};
static int pon_ship_mode_en;
@ -381,7 +383,7 @@ static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay)
int rc = 0;
u32 val;
if (delay == pon->dbc)
if (delay == pon->dbc_time_us)
goto out;
if (pon->pon_input)
@ -409,7 +411,7 @@ static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay)
goto unlock;
}
pon->dbc = delay;
pon->dbc_time_us = delay;
unlock:
if (pon->pon_input)
@ -418,12 +420,34 @@ out:
return rc;
}
static int qpnp_pon_get_dbc(struct qpnp_pon *pon, u32 *delay)
{
int rc;
unsigned int val;
rc = regmap_read(pon->regmap, QPNP_PON_DBC_CTL(pon), &val);
if (rc) {
pr_err("Unable to read pon_dbc_ctl rc=%d\n", rc);
return rc;
}
val &= QPNP_PON_DBC_DELAY_MASK(pon);
if (is_pon_gen2(pon))
*delay = USEC_PER_SEC /
(1 << (QPNP_PON_GEN2_DELAY_BIT_SHIFT - val));
else
*delay = USEC_PER_SEC /
(1 << (QPNP_PON_DELAY_BIT_SHIFT - val));
return rc;
}
static ssize_t qpnp_pon_dbc_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qpnp_pon *pon = dev_get_drvdata(dev);
return snprintf(buf, QPNP_PON_BUFFER_SIZE, "%d\n", pon->dbc);
return snprintf(buf, QPNP_PON_BUFFER_SIZE, "%d\n", pon->dbc_time_us);
}
static ssize_t qpnp_pon_dbc_store(struct device *dev,
@ -777,6 +801,7 @@ qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
u8 pon_rt_bit = 0;
u32 key_status;
uint pon_rt_sts;
u64 elapsed_us;
cfg = qpnp_get_cfg(pon, pon_type);
if (!cfg)
@ -786,6 +811,15 @@ qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
if (!cfg->key_code)
return 0;
if (pon->kpdpwr_dbc_enable && cfg->pon_type == PON_KPDPWR) {
elapsed_us = ktime_us_delta(ktime_get(),
pon->kpdpwr_last_release_time);
if (elapsed_us < pon->dbc_time_us) {
pr_debug("Ignoring kpdpwr event - within debounce time\n");
return 0;
}
}
/* check the RT status to get the current status of the line */
rc = regmap_read(pon->regmap, QPNP_PON_RT_STS(pon), &pon_rt_sts);
if (rc) {
@ -814,6 +848,11 @@ qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
cfg->key_code, pon_rt_sts);
key_status = pon_rt_sts & pon_rt_bit;
if (pon->kpdpwr_dbc_enable && cfg->pon_type == PON_KPDPWR) {
if (!key_status)
pon->kpdpwr_last_release_time = ktime_get();
}
/*
* simulate press event in case release event occurred
* without a press event
@ -2233,7 +2272,21 @@ static int qpnp_pon_probe(struct platform_device *pdev)
}
} else {
rc = qpnp_pon_set_dbc(pon, delay);
if (rc) {
dev_err(&pdev->dev,
"Unable to set PON debounce delay rc=%d\n", rc);
return rc;
}
}
rc = qpnp_pon_get_dbc(pon, &pon->dbc_time_us);
if (rc) {
dev_err(&pdev->dev,
"Unable to get PON debounce delay rc=%d\n", rc);
return rc;
}
pon->kpdpwr_dbc_enable = of_property_read_bool(pon->pdev->dev.of_node,
"qcom,kpdpwr-sw-debounce");
rc = of_property_read_u32(pon->pdev->dev.of_node,
"qcom,warm-reset-poweroff-type",