Loading arch/arm/boot/dts/qcom/msm-pm660l.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -394,6 +394,9 @@ #address-cells = <1>; #size-cells = <1>; reg = <0xec00 0x100>; interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "sc-irq"; qcom,force-module-reenable; lcdb_ldo_vreg: ldo { Loading drivers/regulator/qpnp-lcdb-regulator.c +137 −1 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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) Loading Loading @@ -185,6 +193,7 @@ struct qpnp_lcdb { struct platform_device *pdev; struct regmap *regmap; u32 base; int sc_irq; /* TTW params */ bool ttw_enable; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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; } Loading Loading
arch/arm/boot/dts/qcom/msm-pm660l.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -394,6 +394,9 @@ #address-cells = <1>; #size-cells = <1>; reg = <0xec00 0x100>; interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "sc-irq"; qcom,force-module-reenable; lcdb_ldo_vreg: ldo { Loading
drivers/regulator/qpnp-lcdb-regulator.c +137 −1 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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) Loading Loading @@ -185,6 +193,7 @@ struct qpnp_lcdb { struct platform_device *pdev; struct regmap *regmap; u32 base; int sc_irq; /* TTW params */ bool ttw_enable; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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; } Loading