summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Yang <harryy@codeaurora.org>2016-09-26 11:03:22 -0700
committerNicholas Troast <ntroast@codeaurora.org>2016-10-06 16:30:27 -0700
commita288404dd90a120982ab4c96b99be9908ece7b5e (patch)
tree13da9c7f2358a6df903621377478b230400a987c
parent4ed92c2c0074a305b6f44776d71905ace7a2b8e1 (diff)
qcom-charger: software fix for OTG soft-start
OTG devices with high capacitance could cause a system UVLO due to a large amount of in-rush current drawn from battery. Fix this by regulating the OTG boost start and altering PFM threshold in software. CRs-Fixed: 1048244 Change-Id: I08838d81eb99a424a3fd396582c56b120cbb46cb Signed-off-by: Harry Yang <harryy@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt6
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c16
-rw-r--r--drivers/power/qcom-charger/smb-lib.c69
-rw-r--r--drivers/power/qcom-charger/smb-lib.h3
-rw-r--r--drivers/power/qcom-charger/smb-reg.h10
5 files changed, 100 insertions, 4 deletions
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
index 21404dfc4b7b..12ac75a8608c 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
@@ -53,6 +53,12 @@ Charger specific properties:
Definition: Specifies the USB input current limit in micro-amps.
If the value is not present, 1.5Amps is used as default.
+- qcom,usb-ocl-ua
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the OTG output current limit in micro-amps.
+ If the value is not present, 1.5Amps is used as default
+
- qcom,dc-icl-ua
Usage: optional
Value type: <u32>
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 1b63f51088ee..ee576d300054 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -58,6 +58,13 @@ static struct smb_params v1_params = {
.max_u = 4800000,
.step_u = 25000,
},
+ .otg_cl = {
+ .name = "usb otg current limit",
+ .reg = OTG_CURRENT_LIMIT_CFG_REG,
+ .min_u = 250000,
+ .max_u = 2000000,
+ .step_u = 250000,
+ },
.dc_icl = {
.name = "dc input current limit",
.reg = DCIN_CURRENT_LIMIT_CFG_REG,
@@ -202,6 +209,7 @@ struct smb_dt_props {
bool no_battery;
int fcc_ua;
int usb_icl_ua;
+ int otg_cl_ua;
int dc_icl_ua;
int fv_uv;
int wipower_max_uw;
@@ -226,6 +234,7 @@ module_param_named(
pl_master_percent, __pl_master_percent, int, S_IRUSR | S_IWUSR
);
+#define MICRO_1P5A 1500000
static int smb2_parse_dt(struct smb2 *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -278,6 +287,11 @@ static int smb2_parse_dt(struct smb2 *chip)
chip->dt.usb_icl_ua = -EINVAL;
rc = of_property_read_u32(node,
+ "qcom,otg-cl-ua", &chip->dt.otg_cl_ua);
+ if (rc < 0)
+ chip->dt.otg_cl_ua = MICRO_1P5A;
+
+ rc = of_property_read_u32(node,
"qcom,dc-icl-ua", &chip->dt.dc_icl_ua);
if (rc < 0)
chip->dt.dc_icl_ua = -EINVAL;
@@ -981,6 +995,8 @@ static int smb2_init_hw(struct smb2 *chip)
smblib_get_charge_param(chg, &chg->param.dc_icl,
&chip->dt.dc_icl_ua);
+ chg->otg_cl_ua = chip->dt.otg_cl_ua;
+
/* votes must be cast before configuring software control */
vote(chg->pl_disable_votable,
PL_INDIRECT_VOTER, true, 0);
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index e9c189ae17e7..0067ec5c2ca2 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/regmap.h>
+#include <linux/delay.h>
#include <linux/iio/consumer.h>
#include <linux/power_supply.h>
#include <linux/regulator/driver.h>
@@ -642,6 +643,31 @@ suspend:
return rc;
}
+#define MICRO_250MA 250000
+static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua)
+{
+ int rc = 0;
+
+ rc = smblib_set_charge_param(chg, &chg->param.otg_cl, otg_cl_ua);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't set otg current limit rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* configure PFM/PWM mode for OTG regulator */
+ rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG3_REG,
+ ENG_SSUPPLY_CFG_SKIP_TH_V0P2_BIT,
+ otg_cl_ua > MICRO_250MA ? 1 : 0);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't write DC_ENG_SSUPPLY_CFG3_REG rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
{
@@ -746,14 +772,36 @@ static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
* OTG REGULATOR *
*****************/
+#define OTG_SOFT_START_DELAY_MS 20
int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
+ u8 stat;
int rc = 0;
- rc = regmap_write(chg->regmap, CMD_OTG_REG, OTG_EN_BIT);
- if (rc < 0)
+ rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
+ ENG_BUCKBOOST_HALT1_8_MODE_BIT,
+ ENG_BUCKBOOST_HALT1_8_MODE_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
+ if (rc < 0) {
dev_err(chg->dev, "Couldn't enable OTG regulator rc=%d\n", rc);
+ return rc;
+ }
+
+ msleep(OTG_SOFT_START_DELAY_MS);
+ rc = smblib_read(chg, OTG_STATUS_REG, &stat);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't read OTG_STATUS_REG rc=%d\n", rc);
+ return rc;
+ }
+ if (stat & BOOST_SOFTSTART_DONE_BIT)
+ smblib_otg_cl_config(chg, chg->otg_cl_ua);
return rc;
}
@@ -763,9 +811,22 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int rc = 0;
- rc = regmap_write(chg->regmap, CMD_OTG_REG, 0);
- if (rc < 0)
+ rc = smblib_write(chg, CMD_OTG_REG, 0);
+ if (rc < 0) {
dev_err(chg->dev, "Couldn't disable OTG regulator rc=%d\n", rc);
+ return rc;
+ }
+
+ smblib_otg_cl_config(chg, MICRO_250MA);
+
+ rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
+ ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+
return rc;
}
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index c9732c25dfcd..5b4c2016adc8 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -77,6 +77,7 @@ struct smb_params {
struct smb_chg_param fv;
struct smb_chg_param usb_icl;
struct smb_chg_param icl_stat;
+ struct smb_chg_param otg_cl;
struct smb_chg_param dc_icl;
struct smb_chg_param dc_icl_pt_lv;
struct smb_chg_param dc_icl_pt_hv;
@@ -167,6 +168,8 @@ struct smb_charger {
int thermal_levels;
int *thermal_mitigation;
+ int otg_cl_ua;
+
int fake_capacity;
bool step_chg_enabled;
diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h
index c4ad72e254f9..8a49a8fb38ba 100644
--- a/drivers/power/qcom-charger/smb-reg.h
+++ b/drivers/power/qcom-charger/smb-reg.h
@@ -366,6 +366,9 @@ enum {
#define OTG_EN_SRC_CFG_BIT BIT(1)
#define CONCURRENT_MODE_CFG_BIT BIT(0)
+#define OTG_ENG_OTG_CFG_REG (OTG_BASE + 0xC0)
+#define ENG_BUCKBOOST_HALT1_8_MODE_BIT BIT(0)
+
/* BATIF Peripheral Registers */
/* BATIF Interrupt Bits */
#define BAT_7_RT_STS_BIT BIT(7)
@@ -766,6 +769,13 @@ enum {
ZIN_ICL_HV_MAX_MV = 11000,
};
+#define DC_ENG_SSUPPLY_CFG3_REG (DCIN_BASE + 0xC2)
+#define ENG_SSUPPLY_HI_CAP_BIT BIT(6)
+#define ENG_SSUPPLY_HI_RES_BIT BIT(5)
+#define ENG_SSUPPLY_CFG_SKIP_TH_V0P2_BIT BIT(3)
+#define ENG_SSUPPLY_CFG_SYSOV_TH_4P8_BIT BIT(2)
+#define ENG_SSUPPLY_5V_OV_OPT_BIT BIT(0)
+
/* MISC Peripheral Registers */
#define REVISION1_REG (MISC_BASE + 0x00)
#define DIG_MINOR_MASK GENMASK(7, 0)