From 85635da429d67f9fdf1e19006c0f3b6f5b4bdacf Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Tue, 16 Aug 2016 16:32:38 -0700 Subject: [PATCH] qcom-charger: smb138x: fix buck damage on v1.1 hardware Buck damage was observed because the OOB comparator activated when HSFET was on, causing a direct short from VBUS to ground. Fix this on V1.1 by increasing the OOB comparator threshold. On 2.0 this is fixed by ensuring the OOB comparator activates only after HSFET minimum on time. This in turn guarantees that HSFET and LSFET won't be on at the same time. Since the driver needs to detect the version of the smb, make use of the qpnp-revid module. CRs-Fixed: 1055113 Change-Id: I0a7946db2f1bdacf1974fb508da46f2ed4dadadc Signed-off-by: Abhijeet Dharmapurikar --- .../power/qcom-charger/smb138x-charger.txt | 7 ++ arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi | 6 ++ drivers/power/qcom-charger/smb138x-charger.c | 75 +++++++++++++++++++ include/linux/qpnp/qpnp-revid.h | 3 + 4 files changed, 91 insertions(+) diff --git a/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt b/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt index d41ffcaa4cae..0549c439460c 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/smb138x-charger.txt @@ -24,6 +24,13 @@ Charger specific properties: Standalone/Parallel Master - "qcom,smb138x-charger" Parallel Slave - "qcom,smb138x-parallel-slave" +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of SMB's + revid module. This is used to identify + the SMB subtype. + - qcom,suspend-input Usage: optional Value type: diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi index ba25d2f07736..b84f63ecbd1e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi @@ -370,8 +370,14 @@ #interrupt-cells = <3>; qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; + smb138x_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { compatible = "qcom,smb138x-parallel-slave"; + qcom,pmic-revid = <&smb138x_revid>; reg = <0x1000 0x700>; }; }; diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index e9006cfc0b9e..329ee7210c1f 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "smb-reg.h" #include "smb-lib.h" #include "pmic-voter.h" @@ -29,6 +30,14 @@ #define SMB138X_DEFAULT_FCC_UA 1000000 #define SMB138X_DEFAULT_ICL_UA 1500000 +/* Registers that are not common to be mentioned in smb-reg.h */ +#define SMB2CHG_MISC_ENG_SDCDC_CFG2 (MISC_BASE + 0xC1) +#define ENG_SDCDC_SEL_OOB_VTH_BIT BIT(0) + +enum { + OOB_COMP_WA_BIT = BIT(0), +}; + static struct smb_params v1_params = { .fcc = { .name = "fast charge current", @@ -68,6 +77,7 @@ struct smb_dt_props { }; struct smb138x { + u32 wa_flags; struct smb_charger chg; struct smb_dt_props dt; struct power_supply *parallel_psy; @@ -625,9 +635,56 @@ static int smb138x_init_hw(struct smb138x *chip) return rc; } + if (chip->wa_flags & OOB_COMP_WA_BIT) { + rc = smblib_masked_write(chg, SMB2CHG_MISC_ENG_SDCDC_CFG2, + ENG_SDCDC_SEL_OOB_VTH_BIT, + ENG_SDCDC_SEL_OOB_VTH_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure the oob comp threh rc = %d\n", rc); + return rc; + } + } + return rc; } +static int smb138x_setup_wa_flags(struct smb138x *chip) +{ + struct pmic_revid_data *pmic_rev_id; + struct device_node *revid_dev_node; + + revid_dev_node = of_parse_phandle(chip->chg.dev->of_node, + "qcom,pmic-revid", 0); + if (!revid_dev_node) { + pr_err("Missing qcom,pmic-revid property\n"); + return -EINVAL; + } + + pmic_rev_id = get_revid_data(revid_dev_node); + if (IS_ERR_OR_NULL(pmic_rev_id)) { + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + + switch (pmic_rev_id->pmic_subtype) { + case SMB1381_SUBTYPE: + if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */ + chip->wa_flags |= OOB_COMP_WA_BIT; + break; + default: + pr_err("PMIC subtype %d not supported\n", + pmic_rev_id->pmic_subtype); + return -EINVAL; + } + + return 0; +} + /**************************** * DETERMINE INITIAL STATUS * ****************************/ @@ -857,6 +914,17 @@ static int smb138x_slave_probe(struct smb138x *chip) return rc; } + if (chip->wa_flags & OOB_COMP_WA_BIT) { + rc = smblib_masked_write(chg, SMB2CHG_MISC_ENG_SDCDC_CFG2, + ENG_SDCDC_SEL_OOB_VTH_BIT, + ENG_SDCDC_SEL_OOB_VTH_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure the oob comp threh rc = %d\n", rc); + return rc; + } + } + /* suspend usb input */ rc = smblib_set_usb_suspend(chg, true); if (rc < 0) { @@ -938,6 +1006,13 @@ static int smb138x_probe(struct platform_device *pdev) platform_set_drvdata(pdev, chip); + rc = smb138x_setup_wa_flags(chip); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + pr_err("Couldn't setup wa flags rc = %d\n", rc); + return rc; + } + chip->chg.mode = (enum smb_mode) id->data; switch (chip->chg.mode) { case PARALLEL_MASTER: diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h index 388296c53460..b13ebe50c3d6 100644 --- a/include/linux/qpnp/qpnp-revid.h +++ b/include/linux/qpnp/qpnp-revid.h @@ -201,6 +201,9 @@ /* PMI8937 */ #define PMI8937_SUBTYPE 0x37 +/* SMB1381 */ +#define SMB1381_SUBTYPE 0x17 + struct pmic_revid_data { u8 rev1; u8 rev2;