From 5549356bece921375a2094b05e7fbe0b62115cd2 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 31 Mar 2017 16:18:24 +0530 Subject: [PATCH 1/2] include: qpnp-revid: Add PM660L version info Add PM660L v1.1 version macros. Change-Id: I14c3f2110efc474686df488748b0a671f34ced90 Signed-off-by: Anirudh Ghayal --- include/linux/qpnp/qpnp-revid.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h index a0e2283ef4c9..7254f4d16176 100644 --- a/include/linux/qpnp/qpnp-revid.h +++ b/include/linux/qpnp/qpnp-revid.h @@ -208,6 +208,12 @@ #define PM660_V1P1_REV3 0x01 #define PM660_V1P1_REV4 0x01 +/* PM660L REV_ID */ +#define PM660L_V1P1_REV1 0x00 +#define PM660L_V1P1_REV2 0x00 +#define PM660L_V1P1_REV3 0x01 +#define PM660L_V1P1_REV4 0x01 + /* PMI8998 FAB_ID */ #define PMI8998_FAB_ID_SMIC 0x11 #define PMI8998_FAB_ID_GF 0x30 From 1054280e99393992cc3760552fab5578f4e6673d Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 31 Mar 2017 15:34:05 +0530 Subject: [PATCH 2/2] 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 --- .../regulator/qpnp-lcdb-regulator.txt | 10 +- arch/arm/boot/dts/qcom/msm-pm660l.dtsi | 2 +- drivers/regulator/qpnp-lcdb-regulator.c | 113 ++++++++++++++---- 3 files changed, 92 insertions(+), 33 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt index 63da8ecbfa4c..ed383ce9ea8f 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt @@ -26,12 +26,10 @@ First Level Node - LCDB module Value type: Definition: Base address of the LCDB SPMI peripheral. -- qcom,force-module-reenable - Usage: required if using SW mode for module enable - Value type: - 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: + Definition: Phandle to the PMIC's revid node Touch-to-wake (TTW) properties: diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index bcdbc4ed7c55..7f386957d555 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -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"; diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index aef28dbeb931..724e8a4c00da 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -24,6 +24,7 @@ #include #include #include +#include #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) {