Merge "ARM: dts: msm: Enable Short-Circuit (SC) interrupt for LCDB on PM660L"
This commit is contained in:
commit
bfc0e4b108
2 changed files with 140 additions and 1 deletions
|
@ -394,6 +394,9 @@
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
reg = <0xec00 0x100>;
|
reg = <0xec00 0x100>;
|
||||||
|
interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
|
||||||
|
interrupt-names = "sc-irq";
|
||||||
|
|
||||||
qcom,force-module-reenable;
|
qcom,force-module-reenable;
|
||||||
|
|
||||||
lcdb_ldo_vreg: ldo {
|
lcdb_ldo_vreg: ldo {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/ktime.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
@ -31,6 +32,13 @@
|
||||||
|
|
||||||
#define INT_RT_STATUS_REG 0x10
|
#define INT_RT_STATUS_REG 0x10
|
||||||
#define VREG_OK_RT_STS_BIT BIT(0)
|
#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 LCDB_AUTO_TOUCH_WAKE_CTL_REG 0x40
|
||||||
#define EN_AUTO_TOUCH_WAKE_BIT BIT(7)
|
#define EN_AUTO_TOUCH_WAKE_BIT BIT(7)
|
||||||
|
@ -185,6 +193,7 @@ struct qpnp_lcdb {
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
u32 base;
|
u32 base;
|
||||||
|
int sc_irq;
|
||||||
|
|
||||||
/* TTW params */
|
/* TTW params */
|
||||||
bool ttw_enable;
|
bool ttw_enable;
|
||||||
|
@ -196,6 +205,9 @@ struct qpnp_lcdb {
|
||||||
/* status parameters */
|
/* status parameters */
|
||||||
bool lcdb_enabled;
|
bool lcdb_enabled;
|
||||||
bool settings_saved;
|
bool settings_saved;
|
||||||
|
bool lcdb_sc_disable;
|
||||||
|
int sc_count;
|
||||||
|
ktime_t sc_module_enable_time;
|
||||||
|
|
||||||
struct mutex lcdb_mutex;
|
struct mutex lcdb_mutex;
|
||||||
struct mutex read_write_mutex;
|
struct mutex read_write_mutex;
|
||||||
|
@ -572,8 +584,11 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
|
||||||
int rc = 0, timeout, delay;
|
int rc = 0, timeout, delay;
|
||||||
u8 val = 0;
|
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;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (lcdb->ttw_enable) {
|
if (lcdb->ttw_enable) {
|
||||||
rc = qpnp_lcdb_ttw_exit(lcdb);
|
rc = qpnp_lcdb_ttw_exit(lcdb);
|
||||||
|
@ -676,6 +691,111 @@ static int qpnp_lcdb_disable(struct qpnp_lcdb *lcdb)
|
||||||
return rc;
|
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 MIN_BST_VOLTAGE_MV 4700
|
||||||
#define MAX_BST_VOLTAGE_MV 6250
|
#define MAX_BST_VOLTAGE_MV 6250
|
||||||
#define MIN_VOLTAGE_MV 4000
|
#define MIN_VOLTAGE_MV 4000
|
||||||
|
@ -1554,6 +1674,18 @@ static int qpnp_lcdb_hw_init(struct qpnp_lcdb *lcdb)
|
||||||
return rc;
|
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)) {
|
if (!is_lcdb_enabled(lcdb)) {
|
||||||
rc = qpnp_lcdb_read(lcdb, lcdb->base +
|
rc = qpnp_lcdb_read(lcdb, lcdb->base +
|
||||||
LCDB_MODULE_RDY_REG, &val, 1);
|
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->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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue