regulator: qpnp-lcdb: Add a WA to toggle SC before module_enable
There is a possibility of the NCP failing to turn on due to an invalid (short circuit) SC event before the LCDB module is enabled. Force a SC re-enable to recover from this condition. Enable this for PM660L V1.1. Also, disable the SC handling logic for PM660L to avoid permanently disabling the module due to the above mentioned issue. CRs-Fixed: 2025449 Change-Id: I191d11c35c3d96727874818b8b57fa1c254879bf Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
This commit is contained in:
parent
5549356bec
commit
1054280e99
3 changed files with 92 additions and 33 deletions
|
@ -26,12 +26,10 @@ First Level Node - LCDB module
|
|||
Value type: <prop-encoded-array>
|
||||
Definition: Base address of the LCDB SPMI peripheral.
|
||||
|
||||
- qcom,force-module-reenable
|
||||
Usage: required if using SW mode for module enable
|
||||
Value type: <bool>
|
||||
Definition: This enables the workaround to force enable
|
||||
the vph_pwr_2p5_ok signal required for
|
||||
turning on the LCDB module.
|
||||
- qcom,pmic-revid
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: Phandle to the PMIC's revid node
|
||||
|
||||
Touch-to-wake (TTW) properties:
|
||||
|
||||
|
|
|
@ -397,7 +397,7 @@
|
|||
interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "sc-irq";
|
||||
|
||||
qcom,force-module-reenable;
|
||||
qcom,pmic-revid = <&pm660l_revid>;
|
||||
|
||||
lcdb_ldo_vreg: ldo {
|
||||
label = "ldo";
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/qpnp/qpnp-revid.h>
|
||||
|
||||
#define QPNP_LCDB_REGULATOR_DRIVER_NAME "qcom,qpnp-lcdb-regulator"
|
||||
|
||||
|
@ -192,6 +193,7 @@ struct qpnp_lcdb {
|
|||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
struct regmap *regmap;
|
||||
struct pmic_revid_data *pmic_rev_id;
|
||||
u32 base;
|
||||
int sc_irq;
|
||||
|
||||
|
@ -199,9 +201,6 @@ struct qpnp_lcdb {
|
|||
bool ttw_enable;
|
||||
bool ttw_mode_sw;
|
||||
|
||||
/* top level DT params */
|
||||
bool force_module_reenable;
|
||||
|
||||
/* status parameters */
|
||||
bool lcdb_enabled;
|
||||
bool settings_saved;
|
||||
|
@ -579,6 +578,65 @@ static int qpnp_lcdb_ttw_exit(struct qpnp_lcdb *lcdb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qpnp_lcdb_enable_wa(struct qpnp_lcdb *lcdb)
|
||||
{
|
||||
int rc;
|
||||
u8 val = 0;
|
||||
|
||||
/* required only for PM660L */
|
||||
if (lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE)
|
||||
return 0;
|
||||
|
||||
val = MODULE_EN_BIT;
|
||||
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
|
||||
&val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to enable lcdb rc= %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
val = 0;
|
||||
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
|
||||
&val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to disable lcdb rc= %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* execute the below for rev1.1 */
|
||||
if (lcdb->pmic_rev_id->rev3 == PM660L_V1P1_REV3 &&
|
||||
lcdb->pmic_rev_id->rev4 == PM660L_V1P1_REV4) {
|
||||
/*
|
||||
* delay to make sure that the MID pin – ie the
|
||||
* output of the LCDB boost – returns to 0V
|
||||
* after the module is disabled
|
||||
*/
|
||||
usleep_range(10000, 10100);
|
||||
|
||||
rc = qpnp_lcdb_masked_write(lcdb,
|
||||
lcdb->base + LCDB_MISC_CTL_REG,
|
||||
DIS_SCP_BIT, DIS_SCP_BIT);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to disable SC rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
/* delay for SC-disable to take effect */
|
||||
usleep_range(1000, 1100);
|
||||
|
||||
rc = qpnp_lcdb_masked_write(lcdb,
|
||||
lcdb->base + LCDB_MISC_CTL_REG,
|
||||
DIS_SCP_BIT, 0);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to enable SC rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
/* delay for SC-enable to take effect */
|
||||
usleep_range(1000, 1100);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
|
||||
{
|
||||
int rc = 0, timeout, delay;
|
||||
|
@ -598,31 +656,20 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
|
|||
}
|
||||
}
|
||||
|
||||
rc = qpnp_lcdb_enable_wa(lcdb);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to execute enable_wa rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
val = MODULE_EN_BIT;
|
||||
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
|
||||
&val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to enable lcdb rc= %d\n", rc);
|
||||
pr_err("Failed to disable lcdb rc= %d\n", rc);
|
||||
goto fail_enable;
|
||||
}
|
||||
|
||||
if (lcdb->force_module_reenable) {
|
||||
val = 0;
|
||||
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
|
||||
&val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to enable lcdb rc= %d\n", rc);
|
||||
goto fail_enable;
|
||||
}
|
||||
val = MODULE_EN_BIT;
|
||||
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
|
||||
&val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to disable lcdb rc= %d\n", rc);
|
||||
goto fail_enable;
|
||||
}
|
||||
}
|
||||
|
||||
/* poll for vreg_ok */
|
||||
timeout = 10;
|
||||
delay = lcdb->bst.soft_start_us + lcdb->ldo.soft_start_us +
|
||||
|
@ -1674,7 +1721,8 @@ static int qpnp_lcdb_hw_init(struct qpnp_lcdb *lcdb)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (lcdb->sc_irq >= 0) {
|
||||
if (lcdb->sc_irq >= 0 &&
|
||||
lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) {
|
||||
lcdb->sc_count = 0;
|
||||
rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq,
|
||||
NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT,
|
||||
|
@ -1714,7 +1762,23 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb)
|
|||
{
|
||||
int rc = 0;
|
||||
const char *label;
|
||||
struct device_node *temp, *node = lcdb->dev->of_node;
|
||||
struct device_node *revid_dev_node, *temp, *node = lcdb->dev->of_node;
|
||||
|
||||
revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
|
||||
if (!revid_dev_node) {
|
||||
pr_err("Missing qcom,pmic-revid property - fail driver\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lcdb->pmic_rev_id = get_revid_data(revid_dev_node);
|
||||
if (IS_ERR(lcdb->pmic_rev_id)) {
|
||||
pr_debug("Unable to get revid data\n");
|
||||
/*
|
||||
* revid should to be defined, return -EPROBE_DEFER
|
||||
* until the revid module registers.
|
||||
*/
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
for_each_available_child_of_node(node, temp) {
|
||||
rc = of_property_read_string(temp, "label", &label);
|
||||
|
@ -1742,9 +1806,6 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb)
|
|||
}
|
||||
}
|
||||
|
||||
lcdb->force_module_reenable = of_property_read_bool(node,
|
||||
"qcom,force-module-reenable");
|
||||
|
||||
if (of_property_read_bool(node, "qcom,ttw-enable")) {
|
||||
rc = qpnp_lcdb_parse_ttw(lcdb);
|
||||
if (rc < 0) {
|
||||
|
|
Loading…
Add table
Reference in a new issue