OSDN Git Service

regulator: qpnp-lcdb: Add a WA to toggle SC before module_enable
authorAnirudh Ghayal <aghayal@codeaurora.org>
Fri, 31 Mar 2017 10:04:05 +0000 (15:34 +0530)
committerAnirudh Ghayal <aghayal@codeaurora.org>
Sat, 1 Apr 2017 01:17:53 +0000 (06:47 +0530)
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>
Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
arch/arm/boot/dts/qcom/msm-pm660l.dtsi
drivers/regulator/qpnp-lcdb-regulator.c

index 63da8ec..ed383ce 100644 (file)
@@ -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:
 
index bcdbc4e..7f38695 100644 (file)
                        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";
index aef28db..724e8a4 100644 (file)
@@ -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) {