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:
parent
b1980b6bfe
commit
dfdb97d8b9
2 changed files with 59 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Reference in a new issue