regulator: qpnp-lcdb: Handle short-circuit (SC) event

Handle the SC event in normal and TTW mode. Check if the
SC event is valid and re-enable the module to check
if it goes away. Disable the module altogether if the
SC event persists.

CRs-Fixed: 1083319
Change-Id: I20bd3ca0bd3cf273a2607656e3f51bde1eaf2dc6
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
This commit is contained in:
Anirudh Ghayal 2017-03-05 22:34:37 +05:30
parent 35731dbb93
commit 85d260aee8

View file

@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
@ -31,6 +32,13 @@
#define INT_RT_STATUS_REG 0x10
#define VREG_OK_RT_STS_BIT BIT(0)
#define SC_ERROR_RT_STS_BIT BIT(1)
#define LCDB_STS3_REG 0x0A
#define LDO_VREG_OK_BIT BIT(7)
#define LCDB_STS4_REG 0x0B
#define NCP_VREG_OK_BIT BIT(7)
#define LCDB_AUTO_TOUCH_WAKE_CTL_REG 0x40
#define EN_AUTO_TOUCH_WAKE_BIT BIT(7)
@ -185,6 +193,7 @@ struct qpnp_lcdb {
struct platform_device *pdev;
struct regmap *regmap;
u32 base;
int sc_irq;
/* TTW params */
bool ttw_enable;
@ -196,6 +205,9 @@ struct qpnp_lcdb {
/* status parameters */
bool lcdb_enabled;
bool settings_saved;
bool lcdb_sc_disable;
int sc_count;
ktime_t sc_module_enable_time;
struct mutex lcdb_mutex;
struct mutex read_write_mutex;
@ -572,8 +584,11 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
int rc = 0, timeout, delay;
u8 val = 0;
if (lcdb->lcdb_enabled)
if (lcdb->lcdb_enabled || lcdb->lcdb_sc_disable) {
pr_debug("lcdb_enabled=%d lcdb_sc_disable=%d\n",
lcdb->lcdb_enabled, lcdb->lcdb_sc_disable);
return 0;
}
if (lcdb->ttw_enable) {
rc = qpnp_lcdb_ttw_exit(lcdb);
@ -676,6 +691,111 @@ static int qpnp_lcdb_disable(struct qpnp_lcdb *lcdb)
return rc;
}
#define LCDB_SC_RESET_CNT_DLY_US 1000000
#define LCDB_SC_CNT_MAX 10
static int qpnp_lcdb_handle_sc_event(struct qpnp_lcdb *lcdb)
{
int rc = 0;
s64 elapsed_time_us;
mutex_lock(&lcdb->lcdb_mutex);
rc = qpnp_lcdb_disable(lcdb);
if (rc < 0) {
pr_err("Failed to disable lcdb rc=%d\n", rc);
goto unlock_mutex;
}
/* Check if the SC re-occurred immediately */
elapsed_time_us = ktime_us_delta(ktime_get(),
lcdb->sc_module_enable_time);
if (elapsed_time_us > LCDB_SC_RESET_CNT_DLY_US) {
lcdb->sc_count = 0;
} else if (lcdb->sc_count > LCDB_SC_CNT_MAX) {
pr_err("SC trigged %d times, disabling LCDB forever!\n",
lcdb->sc_count);
lcdb->lcdb_sc_disable = true;
goto unlock_mutex;
}
lcdb->sc_count++;
lcdb->sc_module_enable_time = ktime_get();
/* delay for SC to clear */
usleep_range(10000, 10100);
rc = qpnp_lcdb_enable(lcdb);
if (rc < 0)
pr_err("Failed to enable lcdb rc=%d\n", rc);
unlock_mutex:
mutex_unlock(&lcdb->lcdb_mutex);
return rc;
}
static irqreturn_t qpnp_lcdb_sc_irq_handler(int irq, void *data)
{
struct qpnp_lcdb *lcdb = data;
int rc;
u8 val, val2[2] = {0};
rc = qpnp_lcdb_read(lcdb, lcdb->base + INT_RT_STATUS_REG, &val, 1);
if (rc < 0)
goto irq_handled;
if (val & SC_ERROR_RT_STS_BIT) {
rc = qpnp_lcdb_read(lcdb,
lcdb->base + LCDB_MISC_CTL_REG, &val, 1);
if (rc < 0)
goto irq_handled;
if (val & EN_TOUCH_WAKE_BIT) {
/* blanking time */
usleep_range(300, 310);
/*
* The status registers need to written with any value
* before reading
*/
rc = qpnp_lcdb_write(lcdb,
lcdb->base + LCDB_STS3_REG, val2, 2);
if (rc < 0)
goto irq_handled;
rc = qpnp_lcdb_read(lcdb,
lcdb->base + LCDB_STS3_REG, val2, 2);
if (rc < 0)
goto irq_handled;
if (!(val2[0] & LDO_VREG_OK_BIT) ||
!(val2[1] & NCP_VREG_OK_BIT)) {
rc = qpnp_lcdb_handle_sc_event(lcdb);
if (rc < 0) {
pr_err("Failed to handle SC rc=%d\n",
rc);
goto irq_handled;
}
}
} else {
/* blanking time */
usleep_range(2000, 2100);
/* Read the SC status again to confirm true SC */
rc = qpnp_lcdb_read(lcdb,
lcdb->base + INT_RT_STATUS_REG, &val, 1);
if (rc < 0)
goto irq_handled;
if (val & SC_ERROR_RT_STS_BIT) {
rc = qpnp_lcdb_handle_sc_event(lcdb);
if (rc < 0) {
pr_err("Failed to handle SC rc=%d\n",
rc);
goto irq_handled;
}
}
}
}
irq_handled:
return IRQ_HANDLED;
}
#define MIN_BST_VOLTAGE_MV 4700
#define MAX_BST_VOLTAGE_MV 6250
#define MIN_VOLTAGE_MV 4000
@ -1554,6 +1674,18 @@ static int qpnp_lcdb_hw_init(struct qpnp_lcdb *lcdb)
return rc;
}
if (lcdb->sc_irq >= 0) {
lcdb->sc_count = 0;
rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq,
NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT,
"qpnp_lcdb_sc_irq", lcdb);
if (rc < 0) {
pr_err("Unable to request sc(%d) irq rc=%d\n",
lcdb->sc_irq, rc);
return rc;
}
}
if (!is_lcdb_enabled(lcdb)) {
rc = qpnp_lcdb_read(lcdb, lcdb->base +
LCDB_MODULE_RDY_REG, &val, 1);
@ -1622,6 +1754,10 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb)
lcdb->ttw_enable = true;
}
lcdb->sc_irq = platform_get_irq_byname(lcdb->pdev, "sc-irq");
if (lcdb->sc_irq < 0)
pr_debug("sc irq is not defined\n");
return rc;
}