OSDN Git Service

power: import xiaomi changes
authorJulian Liu <wlootlxt123@gmail.com>
Fri, 6 Sep 2019 06:34:06 +0000 (14:34 +0800)
committer0ranko0P <ranko0p@outlook.com>
Wed, 4 Dec 2019 17:17:31 +0000 (01:17 +0800)
15 files changed:
drivers/power/power_supply_leds.c
drivers/power/power_supply_sysfs.c
drivers/power/reset/msm-poweroff.c
drivers/power/supply/qcom/Kconfig
drivers/power/supply/qcom/Makefile
drivers/power/supply/qcom/battery.c
drivers/power/supply/qcom/fg-core.h
drivers/power/supply/qcom/pmic-voter.c
drivers/power/supply/qcom/qpnp-fg-gen3.c
drivers/power/supply/qcom/qpnp-smb2.c
drivers/power/supply/qcom/smb-lib.c
drivers/power/supply/qcom/smb-lib.h
drivers/power/supply/qcom/smb-reg.h
include/linux/input/qpnp-power-on.h
include/linux/power_supply.h

index 2277ad9..1f622fc 100644 (file)
@@ -113,6 +113,8 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy)
 
 static void power_supply_update_gen_leds(struct power_supply *psy)
 {
+       /* xiaomi project don't support this feature, return skip this feature*/
+#if 0
        union power_supply_propval online;
 
        if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
@@ -124,6 +126,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy)
                led_trigger_event(psy->online_trig, LED_FULL);
        else
                led_trigger_event(psy->online_trig, LED_OFF);
+#endif
 }
 
 static int power_supply_create_gen_triggers(struct power_supply *psy)
index 36217ae..c1b8ce3 100644 (file)
@@ -132,6 +132,8 @@ static ssize_t power_supply_show_property(struct device *dev,
 
        if (off == POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT)
                return sprintf(buf, "%lld\n", value.int64val);
+       else if (off == POWER_SUPPLY_PROP_TYPE_RECHECK)
+               return scnprintf(buf, PAGE_SIZE, "0x%x\n", value.intval);
        else
                return sprintf(buf, "%d\n", value.intval);
 }
@@ -271,6 +273,7 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(current_qnovo),
        POWER_SUPPLY_ATTR(voltage_qnovo),
        POWER_SUPPLY_ATTR(rerun_aicl),
+       POWER_SUPPLY_ATTR(charger_type),
        POWER_SUPPLY_ATTR(cycle_count_id),
        POWER_SUPPLY_ATTR(safety_timer_expired),
        POWER_SUPPLY_ATTR(restricted_charging),
@@ -298,6 +301,7 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(ctm_current_max),
        POWER_SUPPLY_ATTR(hw_current_max),
        POWER_SUPPLY_ATTR(real_type),
+       POWER_SUPPLY_ATTR(hvdcp3_type),
        POWER_SUPPLY_ATTR(pr_swap),
        POWER_SUPPLY_ATTR(cc_step),
        POWER_SUPPLY_ATTR(cc_step_sel),
@@ -305,6 +309,8 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(pd_voltage_max),
        POWER_SUPPLY_ATTR(pd_voltage_min),
        POWER_SUPPLY_ATTR(sdp_current_max),
+       POWER_SUPPLY_ATTR(rerun_apsd),
+       POWER_SUPPLY_ATTR(type_recheck),
        POWER_SUPPLY_ATTR(fcc_stepper_enable),
        POWER_SUPPLY_ATTR(ignore_false_negative_isense),
        POWER_SUPPLY_ATTR(battery_info),
index 02079fa..7421039 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -84,7 +85,7 @@ static struct notifier_block panic_blk = {
 #endif
 
 static int dload_type = SCM_DLOAD_FULLDUMP;
-static int download_mode = 1;
+static int download_mode;
 static struct kobject dload_kobj;
 static void *dload_mode_addr, *dload_type_addr;
 static bool dload_mode_enabled;
@@ -153,7 +154,7 @@ static void set_dload_mode(int on)
        dload_mode_enabled = on;
 }
 
-static bool get_dload_mode(void)
+int get_dload_mode(void)
 {
        return dload_mode_enabled;
 }
@@ -312,7 +313,10 @@ static void msm_restart_prepare(const char *cmd)
                qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);
        }
 
-       if (cmd != NULL) {
+       if (in_panic) {
+               qpnp_pon_set_restart_reason(PON_RESTART_REASON_PANIC);
+               qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET);
+       } else if (cmd != NULL) {
                if (!strncmp(cmd, "bootloader", 10)) {
                        qpnp_pon_set_restart_reason(
                                PON_RESTART_REASON_BOOTLOADER);
@@ -339,33 +343,22 @@ static void msm_restart_prepare(const char *cmd)
                        __raw_writel(0x7766550a, restart_reason);
                } else if (!strncmp(cmd, "oem-", 4)) {
                        unsigned long code;
-                       unsigned long reset_reason;
                        int ret;
                        ret = kstrtoul(cmd + 4, 16, &code);
-                       if (!ret) {
-                               /* Bit-2 to bit-7 of SOFT_RB_SPARE for hard
-                                * reset reason:
-                                * Value 0 to 31 for common defined features
-                                * Value 32 to 63 for oem specific features
-                                */
-                               reset_reason = code +
-                                               PON_RESTART_REASON_OEM_MIN;
-                               if (reset_reason > PON_RESTART_REASON_OEM_MAX ||
-                                  reset_reason < PON_RESTART_REASON_OEM_MIN) {
-                                       pr_err("Invalid oem reset reason: %lx\n",
-                                               reset_reason);
-                               } else {
-                                       qpnp_pon_set_restart_reason(
-                                               reset_reason);
-                               }
+                       if (!ret)
                                __raw_writel(0x6f656d00 | (code & 0xff),
                                             restart_reason);
-                       }
                } else if (!strncmp(cmd, "edl", 3)) {
+                       if (0) {
                        enable_emergency_dload_mode();
+                       }
                } else {
+                       qpnp_pon_set_restart_reason(PON_RESTART_REASON_NORMAL);
                        __raw_writel(0x77665501, restart_reason);
                }
+       } else {
+               qpnp_pon_set_restart_reason(PON_RESTART_REASON_NORMAL);
+               __raw_writel(0x77665501, restart_reason);
        }
 
        flush_cache_all();
index b919c68..47b2017 100644 (file)
@@ -1,23 +1,5 @@
 menu "Qualcomm Technologies Inc Charger and Fuel Gauge support"
 
-config QPNP_SMBCHARGER
-       tristate "QPNP SMB Charger driver"
-       depends on MFD_SPMI_PMIC
-       help
-         Say Y here to enable the dual path switch mode battery charger which
-         supports USB detection and battery charging up to 3A.
-         The driver also offers relevant information to userspace via the
-         power supply framework.
-
-config QPNP_FG
-       tristate "QPNP fuel gauge driver"
-       depends on MFD_SPMI_PMIC
-       help
-         Say Y here to enable the Fuel Gauge driver. This adds support for
-         battery fuel gauging and state of charge of battery connected to the
-         fuel gauge. The state of charge is reported through a BMS power
-         supply property and also sends uevents when the capacity is updated.
-
 config QPNP_FG_GEN3
        tristate "QPNP GEN3 fuel gauge driver"
        depends on MFD_SPMI_PMIC
index 92310ef..87ab2b2 100644 (file)
@@ -1,5 +1,3 @@
-obj-$(CONFIG_QPNP_SMBCHARGER)  += qpnp-smbcharger.o batterydata-lib.o pmic-voter.o
-obj-$(CONFIG_QPNP_FG)          += qpnp-fg.o
 obj-$(CONFIG_QPNP_FG_GEN3)     += qpnp-fg-gen3.o fg-memif.o fg-util.o
 obj-$(CONFIG_SMB135X_CHARGER)   += smb135x-charger.o pmic-voter.o
 obj-$(CONFIG_SMB1351_USB_CHARGER) +=  battery.o smb1351-charger.o pmic-voter.o
index afae88e..74217a9 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2017,2019 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -85,6 +86,7 @@ struct pl_data *the_chip;
 
 enum print_reason {
        PR_PARALLEL     = BIT(0),
+       PR_OEM          = BIT(1),
 };
 
 static int debug_mask;
@@ -241,7 +243,12 @@ static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr,
        if (kstrtoul(ubuf, 10, &val))
                return -EINVAL;
 
-       chip->slave_pct = val;
+       pl_dbg(chip, PR_OEM, "Parallel CT %ld\n", val);
+       if (val >= 50 && val <= 100)
+               chip->slave_pct = 50;
+       else
+               chip->slave_pct = val;
+
        rerun_election(chip->fcc_votable);
        rerun_election(chip->fv_votable);
        split_settled(chip);
@@ -603,7 +610,7 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
                }
        }
 
-       pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
+       pl_dbg(chip, PR_OEM, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
                   master_fcc_ua, slave_fcc_ua,
                   (master_fcc_ua * 100) / total_fcc_ua,
                   (slave_fcc_ua * 100) / total_fcc_ua);
@@ -849,6 +856,8 @@ static int usb_icl_vote_callback(struct votable *votable, void *data,
        if (client == NULL)
                icl_ua = INT_MAX;
 
+       pr_info("%s: set icl %d\n", __func__, icl_ua);
+
        /*
         * Disable parallel for new ICL vote - the call to split_settled will
         * ensure that all the input current limit gets assigned to the main
index 076cd49..4e42118 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -301,6 +302,7 @@ struct fg_batt_props {
        int             float_volt_uv;
        int             vbatt_full_mv;
        int             fastchg_curr_ma;
+       int             nom_cap_uah;
 };
 
 struct fg_cyc_ctr_data {
@@ -384,6 +386,22 @@ static const struct fg_pt fg_tsmc_osc_table[] = {
        {  90,          444992 },
 };
 
+#define BATT_MA_AVG_SAMPLES            8
+struct batt_params {
+       bool            update_now;
+       int             batt_raw_soc;
+       int             batt_soc;
+       int             samples_num;
+       int             samples_index;
+       int             batt_ma_avg_samples[BATT_MA_AVG_SAMPLES];
+       int             batt_ma_avg;
+       int             batt_ma_prev;
+       int             batt_ma;
+       int             batt_mv;
+       int             batt_temp;
+       struct timespec         last_soc_change_time;
+};
+
 struct fg_chip {
        struct device           *dev;
        struct pmic_revid_data  *pmic_rev_id;
@@ -452,14 +470,18 @@ struct fg_chip {
        bool                    esr_flt_cold_temp_en;
        bool                    slope_limit_en;
        bool                    use_ima_single_mode;
+       bool                    report_full;
        bool                    qnovo_enable;
        bool                    suspended;
+       struct batt_params      param;
+       struct delayed_work     soc_monitor_work;
        struct completion       soc_update;
        struct completion       soc_ready;
        struct delayed_work     profile_load_work;
        struct work_struct      status_change_work;
        struct delayed_work     ttf_work;
        struct delayed_work     sram_dump_work;
+       struct delayed_work     soc_work;
        struct work_struct      esr_filter_work;
        struct alarm            esr_filter_alarm;
        ktime_t                 last_delta_temp_time;
index 3d0a718..507c4da 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -411,6 +412,13 @@ int vote(struct votable *votable, const char *client_str, bool enabled, int val)
                return -EINVAL;
        }
 
+       if (strcmp(votable->name, "FG_WS") != 0) {
+               pr_info("%s: current vote is now %d voted by %s,%d,previous voted %d\n",
+                                       votable->name, effective_result,
+                                       get_client_str(votable, effective_id),
+                                       effective_id, votable->effective_result);
+       }
+
        /*
         * Note that the callback is called with a NULL string and -EINVAL
         * result when there are no enabled votes
index f982b7d..e8bc404 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +23,7 @@
 #include <linux/qpnp/qpnp-revid.h>
 #include "fg-core.h"
 #include "fg-reg.h"
+#include <linux/ktime.h>
 
 #define FG_GEN3_DEV_NAME       "qcom,fg-gen3"
 
@@ -390,7 +392,7 @@ static struct fg_alg_flag pmi8998_v2_alg_flags[] = {
        },
 };
 
-static int fg_gen3_debug_mask;
+static int fg_gen3_debug_mask = FG_IRQ | FG_STATUS;
 module_param_named(
        debug_mask, fg_gen3_debug_mask, int, S_IRUSR | S_IWUSR
 );
@@ -760,6 +762,7 @@ static int fg_get_msoc_raw(struct fg_chip *chip, int *val)
 
 #define FULL_CAPACITY  100
 #define FULL_SOC_RAW   255
+#define FULL_SOC_REPORT_THR    250
 static int fg_get_msoc(struct fg_chip *chip, int *msoc)
 {
        int rc;
@@ -768,19 +771,14 @@ static int fg_get_msoc(struct fg_chip *chip, int *msoc)
        if (rc < 0)
                return rc;
 
-       /*
-        * To have better endpoints for 0 and 100, it is good to tune the
-        * calculation discarding values 0 and 255 while rounding off. Rest
-        * of the values 1-254 will be scaled to 1-99. DIV_ROUND_UP will not
-        * be suitable here as it rounds up any value higher than 252 to 100.
-        */
-       if (*msoc == FULL_SOC_RAW)
-               *msoc = 100;
-       else if (*msoc == 0)
-               *msoc = 0;
-       else
-               *msoc = DIV_ROUND_CLOSEST((*msoc - 1) * (FULL_CAPACITY - 2),
-                               FULL_SOC_RAW - 2) + 1;
+       if ((*msoc >= FULL_SOC_REPORT_THR)
+                       && (*msoc < FULL_SOC_RAW) && chip->report_full) {
+               *msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW) + 1;
+               if (*msoc >= FULL_CAPACITY)
+                       *msoc = FULL_CAPACITY;
+       } else
+               *msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW);
+
        return 0;
 }
 
@@ -1029,6 +1027,13 @@ static int fg_get_batt_profile(struct fg_chip *chip)
                chip->bp.vbatt_full_mv = -EINVAL;
        }
 
+       rc = of_property_read_u32(profile_node, "qcom,nom-batt-capacity-mah",
+                       &chip->bp.nom_cap_uah);
+       if (rc < 0) {
+               pr_err("battery nominal capacity unavailable, rc:%d\n", rc);
+               chip->bp.nom_cap_uah = -EINVAL;
+       }
+
        data = of_get_property(profile_node, "qcom,fg-profile-data", &len);
        if (!data) {
                pr_err("No profile data available\n");
@@ -1155,7 +1160,7 @@ static void fg_notify_charger(struct fg_chip *chip)
                        rc);
                return;
        }
-
+/*
        prop.intval = chip->bp.fastchg_curr_ma * 1000;
        rc = power_supply_set_property(chip->batt_psy,
                        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
@@ -1164,7 +1169,7 @@ static void fg_notify_charger(struct fg_chip *chip)
                        rc);
                return;
        }
-
+*/
        fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
 }
 
@@ -2040,6 +2045,7 @@ static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
        return 0;
 }
 
+#define DEFAULT_RECHARGE_SOC_RAW 0xfd
 static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
 {
        u8 buf;
@@ -2052,6 +2058,11 @@ static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
                return 0;
 
        fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf);
+
+       if ((buf <= DEFAULT_RECHARGE_SOC_RAW)
+                       && (chip->health != POWER_SUPPLY_HEALTH_WARM))
+               buf += 1;
+
        rc = fg_sram_write(chip,
                        chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
                        chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf,
@@ -2088,40 +2099,27 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip)
         * the recharge SOC threshold based on the monotonic SOC at which
         * the charge termination had happened.
         */
-       if (is_input_present(chip)) {
-               if (chip->charge_done) {
-                       if (!chip->recharge_soc_adjusted) {
-                               /* Get raw monotonic SOC for calculation */
-                               rc = fg_get_msoc(chip, &msoc);
-                               if (rc < 0) {
-                                       pr_err("Error in getting msoc, rc=%d\n",
-                                               rc);
-                                       return rc;
-                               }
-
-                               /* Adjust the recharge_soc threshold */
-                               new_recharge_soc = msoc - (FULL_CAPACITY -
-                                                               recharge_soc);
-                               chip->recharge_soc_adjusted = true;
-                       } else {
-                               /* adjusted already, do nothing */
-                               return 0;
-                       }
-               } else {
-                       if (!chip->recharge_soc_adjusted)
-                               return 0;
-
-                       if (chip->health != POWER_SUPPLY_HEALTH_GOOD)
-                               return 0;
-
-                       /* Restore the default value */
-                       new_recharge_soc = recharge_soc;
-                       chip->recharge_soc_adjusted = false;
+       if (is_input_present(chip) && !chip->recharge_soc_adjusted
+               && chip->charge_done) {
+               if (chip->health == POWER_SUPPLY_HEALTH_GOOD)
+                       return 0;
+               /* Get raw monotonic SOC for calculation */
+               rc = fg_get_msoc(chip, &msoc);
+               if (rc < 0) {
+                       pr_err("Error in getting msoc, rc=%d\n", rc);
+                       return rc;
                }
-       } else {
+
+               /* Adjust the recharge_soc threshold */
+               new_recharge_soc = msoc - (FULL_CAPACITY - recharge_soc);
+               chip->recharge_soc_adjusted = true;
+       } else if ((!is_input_present(chip) || chip->health == POWER_SUPPLY_HEALTH_GOOD)
+                                               && chip->recharge_soc_adjusted) {
                /* Restore the default value */
                new_recharge_soc = recharge_soc;
                chip->recharge_soc_adjusted = false;
+       } else {
+               return 0;
        }
 
        rc = fg_set_recharge_soc(chip, new_recharge_soc);
@@ -2515,6 +2513,7 @@ static void fg_ttf_update(struct fg_chip *chip)
        int delay_ms;
        union power_supply_propval prop = {0, };
        int online = 0;
+       int msoc = 0;
 
        if (usb_psy_initialized(chip)) {
                rc = power_supply_get_property(chip->usb_psy,
@@ -2549,6 +2548,24 @@ static void fg_ttf_update(struct fg_chip *chip)
                online = online || prop.intval;
        }
 
+       chip->charge_done = prop.intval;
+       if (chip->charge_done && !chip->report_full) {
+               chip->report_full = true;
+       } else if (!chip->charge_done && chip->report_full) {
+               rc = fg_get_msoc_raw(chip, &msoc);
+               if (rc < 0)
+                       pr_err("Error in getting msoc, rc=%d\n", rc);
+               if (msoc < FULL_SOC_REPORT_THR)
+                       chip->report_full = false;
+       }
+
+       rc = power_supply_get_property(chip->batt_psy,
+                       POWER_SUPPLY_PROP_HEALTH, &prop);
+       if (rc < 0) {
+               pr_err("Error in getting battery health, rc=%d\n", rc);
+               return;
+       }
+       chip->health = prop.intval;
 
        if (chip->online_status == online)
                return;
@@ -2693,7 +2710,8 @@ out:
 
 static int fg_get_cycle_count(struct fg_chip *chip)
 {
-       int count;
+       int count = 0;
+       int i = 0;
 
        if (!chip->cyc_ctr.en)
                return 0;
@@ -2702,17 +2720,42 @@ static int fg_get_cycle_count(struct fg_chip *chip)
                return -EINVAL;
 
        mutex_lock(&chip->cyc_ctr.lock);
-       count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1];
+       for (i = 0; i < BUCKET_COUNT; i++)
+               count += chip->cyc_ctr.count[i];
+       count /= BUCKET_COUNT;
        mutex_unlock(&chip->cyc_ctr.lock);
        return count;
 }
 
+static int fg_set_cycle_count(struct fg_chip *chip, int value)
+{
+       int rc = 0;
+       int i = 0;
+       u8 data[2];
+
+       for (i = 0; i < BUCKET_COUNT; i++) {
+               data[0] = value & 0xFF;
+               data[1] = value >> 8;
+
+               rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (i / 2),
+                               CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2,
+                               FG_IMA_DEFAULT);
+               if (rc < 0)
+                       pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
+                               i, rc);
+               else
+                       chip->cyc_ctr.count[i] = value;
+       }
+       return rc;
+}
+
 static void status_change_work(struct work_struct *work)
 {
        struct fg_chip *chip = container_of(work,
                        struct fg_chip, status_change_work);
        union power_supply_propval prop = {0, };
        int rc, batt_temp;
+       int msoc = 0;
 
        if (!batt_psy_initialized(chip)) {
                fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
@@ -2726,6 +2769,7 @@ static void status_change_work(struct work_struct *work)
                goto out;
        }
 
+       chip->prev_charge_status = chip->charge_status;
        chip->charge_status = prop.intval;
        rc = power_supply_get_property(chip->batt_psy,
                        POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
@@ -2743,6 +2787,16 @@ static void status_change_work(struct work_struct *work)
        }
 
        chip->charge_done = prop.intval;
+       if (chip->charge_done && !chip->report_full) {
+               chip->report_full = true;
+       } else if (!chip->charge_done && chip->report_full) {
+               rc = fg_get_msoc_raw(chip, &msoc);
+               if (rc < 0)
+                       pr_err("Error in getting msoc, rc=%d\n", rc);
+               if (msoc < FULL_SOC_REPORT_THR)
+                       chip->report_full = false;
+       }
+
        fg_cycle_counter_update(chip);
        fg_cap_learning_update(chip);
 
@@ -2780,7 +2834,7 @@ static void status_change_work(struct work_struct *work)
        }
 
        fg_ttf_update(chip);
-       chip->prev_charge_status = chip->charge_status;
+
 out:
        fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
                chip->charge_status, chip->charge_type, chip->charge_done);
@@ -3518,8 +3572,12 @@ static int fg_update_maint_soc(struct fg_chip *chip)
                }
        }
 
-       fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
-               msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
+       if (msoc != chip->last_msoc)
+               power_supply_changed(chip->batt_psy);
+
+       pr_err("msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
+                       msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
+
        chip->last_msoc = msoc;
 out:
        mutex_unlock(&chip->charge_full_lock);
@@ -3738,6 +3796,9 @@ static int fg_psy_get_property(struct power_supply *psy,
        switch (psp) {
        case POWER_SUPPLY_PROP_CAPACITY:
                rc = fg_get_prop_capacity(chip, &pval->intval);
+
+               if (chip->param.batt_soc >= 0)
+                       pval->intval = chip->param.batt_soc;
                break;
        case POWER_SUPPLY_PROP_CAPACITY_RAW:
                rc = fg_get_msoc_raw(chip, &pval->intval);
@@ -3789,7 +3850,10 @@ static int fg_psy_get_property(struct power_supply *psy,
                rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval);
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-               pval->intval = chip->cl.nom_cap_uah;
+               if (-EINVAL != chip->bp.nom_cap_uah)
+                       pval->intval = chip->bp.nom_cap_uah * 1000;
+               else
+                       pval->intval = chip->cl.nom_cap_uah;
                break;
        case POWER_SUPPLY_PROP_RESISTANCE_ID:
                pval->intval = chip->batt_id_ohms;
@@ -3879,6 +3943,10 @@ static int fg_psy_set_property(struct power_supply *psy,
                        return -EINVAL;
                }
                break;
+       case POWER_SUPPLY_PROP_CYCLE_COUNT:
+               rc = fg_set_cycle_count(chip, pval->intval);
+               pr_info("Cycle count is modified to %d by userspace\n", pval->intval);
+       break;
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
                rc = fg_set_constant_chg_voltage(chip, pval->intval);
                break;
@@ -3962,6 +4030,7 @@ static int fg_property_is_writeable(struct power_supply *psy,
 {
        switch (psp) {
        case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
+       case POWER_SUPPLY_PROP_CYCLE_COUNT:
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
        case POWER_SUPPLY_PROP_CC_STEP:
        case POWER_SUPPLY_PROP_CC_STEP_SEL:
@@ -4307,12 +4376,10 @@ static int fg_hw_init(struct fg_chip *chip)
                return rc;
        }
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
        rc = fg_sram_masked_write(chip, 19, 0, 0x08, 0x08, FG_IMA_DEFAULT);
        if (rc < 0) {
                pr_err("Error in writing cc soc auto clear rc=%d\n", rc);
        }
-#endif
 
        fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
                chip->dt.esr_pulse_thresh_ma, buf);
@@ -4572,9 +4639,6 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
        if (rc < 0)
                pr_err("Error in adjusting timebase, rc=%d\n", rc);
 
-       if (batt_psy_initialized(chip))
-               power_supply_changed(chip->batt_psy);
-
        return IRQ_HANDLED;
 }
 
@@ -5049,6 +5113,12 @@ static int fg_parse_dt(struct fg_chip *chip)
                                rc);
        }
 
+       pr_info("%s: jeita threshold %d, %d, %d, %d\n", __func__,
+                                               chip->dt.jeita_thresholds[JEITA_COLD],
+                                               chip->dt.jeita_thresholds[JEITA_COOL],
+                                               chip->dt.jeita_thresholds[JEITA_WARM],
+                                               chip->dt.jeita_thresholds[JEITA_HOT]);
+
        if (of_property_count_elems_of_size(node,
                "qcom,battery-thermal-coefficients",
                sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
@@ -5242,6 +5312,223 @@ static int fg_parse_dt(struct fg_chip *chip)
        return 0;
 }
 
+#define SOC_WORK_MS     20000
+
+static void soc_work_fn(struct work_struct *work)
+{
+       struct fg_chip *chip = container_of(work,
+                               struct fg_chip,
+                               soc_work.work);
+       int msoc = 0, esr_uohms = 0, curr_ua = 0, volt_uv = 0, temp = 0;
+       int soc = 0;
+       int cycle_count = 0;
+       int rc;
+       static int prev_soc = -EINVAL;
+
+       rc = fg_get_prop_capacity(chip, &soc);
+       if (rc < 0)
+               pr_err("Error in getting capacity, rc=%d\n", rc);
+
+       rc = fg_get_msoc_raw(chip, &msoc);
+       if (rc < 0)
+               pr_err("Error in getting msoc, rc=%d\n", rc);
+
+       rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
+       if (rc < 0)
+               pr_err("failed to get ESR, rc=%d\n", rc);
+
+       fg_get_battery_current(chip, &curr_ua);
+       if (rc < 0)
+               pr_err("failed to get current, rc=%d\n", rc);
+
+       rc = fg_get_battery_voltage(chip, &volt_uv);
+       if (rc < 0)
+               pr_err("failed to get voltage, rc=%d\n", rc);
+
+       rc = fg_get_battery_temp(chip, &temp);
+       if (rc < 0)
+               pr_err("failed to get temp, rc=%d\n", rc);
+
+       cycle_count = fg_get_cycle_count(chip);
+
+       pr_info("adjust_soc: s %d r %d i %d v %d t %d cc %d m 0x%02x\n",
+                       soc, esr_uohms, curr_ua, volt_uv, temp, cycle_count, msoc);
+
+       if (temp < 450 && chip->last_batt_temp >= 450) {
+               /* follow the way that fg_notifier_cb use wake lock */
+               pm_stay_awake(chip->dev);
+               schedule_work(&chip->status_change_work);
+       }
+
+       chip->last_batt_temp = temp;
+
+       /* if soc changes, report power supply change uevent */
+       if (soc != prev_soc) {
+               if (chip->fg_psy)
+                       power_supply_changed(chip->fg_psy);
+               prev_soc = soc;
+       }
+
+       schedule_delayed_work(
+               &chip->soc_work, msecs_to_jiffies(SOC_WORK_MS));
+}
+
+static int calculate_delta_time(struct timespec *time_stamp, int *delta_time_s)
+{
+       struct timespec now_time;
+
+       /* default to delta time = 0 if anything fails */
+       *delta_time_s = 0;
+
+       get_monotonic_boottime(&now_time);
+
+       *delta_time_s = (now_time.tv_sec - time_stamp->tv_sec);
+
+       /* remember this time */
+       *time_stamp = now_time;
+       return 0;
+}
+
+static int calculate_average_current(struct fg_chip *chip)
+{
+       int i;
+       int iavg_ma = chip->param.batt_ma;
+
+       /* only continue if ibat has changed */
+       if (chip->param.batt_ma == chip->param.batt_ma_prev)
+               goto unchanged;
+       else
+               chip->param.batt_ma_prev = chip->param.batt_ma;
+
+       chip->param.batt_ma_avg_samples[chip->param.samples_index] = iavg_ma;
+       chip->param.samples_index = (chip->param.samples_index + 1) % BATT_MA_AVG_SAMPLES;
+       chip->param.samples_num++;
+
+       if (chip->param.samples_num >= BATT_MA_AVG_SAMPLES)
+               chip->param.samples_num = BATT_MA_AVG_SAMPLES;
+
+       if (chip->param.samples_num) {
+               iavg_ma = 0;
+               /* maintain a AVG_SAMPLES sample average of ibat */
+               for (i = 0; i < chip->param.samples_num; i++) {
+                       pr_debug("iavg_samples_ma[%d] = %d\n", i, chip->param.batt_ma_avg_samples[i]);
+                       iavg_ma += chip->param.batt_ma_avg_samples[i];
+               }
+               chip->param.batt_ma_avg = DIV_ROUND_CLOSEST(iavg_ma, chip->param.samples_num);
+       }
+
+unchanged:
+       pr_info("current_now_ma=%d averaged_iavg_ma=%d\n",
+                                                       chip->param.batt_ma, chip->param.batt_ma_avg);
+       return chip->param.batt_ma_avg;
+}
+
+static void fg_battery_soc_smooth_tracking(struct fg_chip *chip)
+{
+       int delta_time = 0;
+       int soc_changed;
+       int last_batt_soc = chip->param.batt_soc;
+       int time_since_last_change_sec;
+
+       struct timespec last_change_time = chip->param.last_soc_change_time;
+
+       calculate_delta_time(&last_change_time, &time_since_last_change_sec);
+
+       if (chip->param.batt_temp > 150) {
+               /* Battery in normal temperture */
+               if (chip->param.batt_ma < 0 ||
+                               (abs(chip->param.batt_raw_soc - chip->param.batt_soc) > 2))
+                       delta_time = time_since_last_change_sec / 30;
+               else
+                       delta_time = time_since_last_change_sec / 60;
+       } else {
+               /* Battery in low temperture */
+               calculate_average_current(chip);
+               /* Calculated average current > 1000mA */
+               if (chip->param.batt_ma_avg > 1000000 ||
+                               (abs(chip->param.batt_raw_soc - chip->param.batt_soc) > 2))
+                       /* Heavy loading current, ignore battery soc limit*/
+                       delta_time = time_since_last_change_sec / 10;
+               else
+                       delta_time = time_since_last_change_sec / 20;
+       }
+
+       if (delta_time < 0)
+               delta_time = 0;
+
+       soc_changed = min(1, delta_time);
+
+       if (last_batt_soc >= 0) {
+               if (last_batt_soc != 100
+                               && chip->param.batt_raw_soc >= 95
+                               && chip->charge_status == POWER_SUPPLY_STATUS_FULL)
+
+                       last_batt_soc = chip->param.update_now ?
+                               100 : last_batt_soc + soc_changed;
+               else if (last_batt_soc < chip->param.batt_raw_soc &&
+                                       chip->param.batt_ma < 0)
+                       /* Battery in charging status
+                        * update the soc when resuming device
+                        */
+                       last_batt_soc = chip->param.update_now ?
+                               chip->param.batt_raw_soc : last_batt_soc + soc_changed;
+               else if (last_batt_soc > chip->param.batt_raw_soc
+                                       && chip->param.batt_ma > 0)
+                       /* Battery in discharging status
+                        * update the soc when resuming device
+                        */
+                       last_batt_soc = chip->param.update_now ?
+                               chip->param.batt_raw_soc : last_batt_soc - soc_changed;
+
+               chip->param.update_now = false;
+       } else {
+               last_batt_soc = chip->param.batt_raw_soc;
+       }
+
+       if (chip->param.batt_soc != last_batt_soc) {
+               chip->param.batt_soc = last_batt_soc;
+               chip->param.last_soc_change_time = last_change_time;
+               if (chip->batt_psy)
+                       power_supply_changed(chip->batt_psy);
+       }
+
+       pr_info("soc:%d, last_soc:%d, raw_soc:%d, soc_changed:%d.\n",
+                       chip->param.batt_soc, last_batt_soc,
+                       chip->param.batt_raw_soc, soc_changed);
+}
+
+#define MONITOR_SOC_WAIT_MS                                    1000
+#define MONITOR_SOC_WAIT_PER_MS             10000
+static void soc_monitor_work(struct work_struct *work)
+{
+       int rc;
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct fg_chip *chip = container_of(dwork,
+                       struct fg_chip, soc_monitor_work);
+
+       rc = fg_get_battery_current(chip, &chip->param.batt_ma);
+       if (rc < 0)
+               pr_err("failded to get battery current, rc=%d\n", rc);
+
+       rc = fg_get_prop_capacity(chip, &chip->param.batt_raw_soc);
+       if (rc < 0)
+               pr_err("failed to get battery capacity, rc=%d\n", rc);
+
+       rc = fg_get_battery_temp(chip, &chip->param.batt_temp);
+       if (rc < 0)
+               pr_err("failed to get battery temperature, rc=%d\n", rc);
+
+       if (chip->soc_reporting_ready)
+               fg_battery_soc_smooth_tracking(chip);
+
+       pr_info("soc:%d, raw_soc:%d, c:%d, s:%d\n",
+                       chip->param.batt_soc, chip->param.batt_raw_soc,
+                       chip->param.batt_ma, chip->charge_status);
+
+       schedule_delayed_work(&chip->soc_monitor_work,
+                       msecs_to_jiffies(MONITOR_SOC_WAIT_PER_MS));
+}
+
 static void fg_cleanup(struct fg_chip *chip)
 {
        alarm_try_to_cancel(&chip->esr_filter_alarm);
@@ -5353,10 +5640,12 @@ static int fg_gen3_probe(struct platform_device *pdev)
        spin_lock_init(&chip->suspend_lock);
        init_completion(&chip->soc_update);
        init_completion(&chip->soc_ready);
+       INIT_DELAYED_WORK(&chip->soc_monitor_work, soc_monitor_work);
        INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
        INIT_WORK(&chip->status_change_work, status_change_work);
        INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
        INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
+       INIT_DELAYED_WORK(&chip->soc_work, soc_work_fn);
        INIT_WORK(&chip->esr_filter_work, esr_filter_work);
        alarm_init(&chip->esr_filter_alarm, ALARM_BOOTTIME,
                        fg_esr_filter_alarm_cb);
@@ -5438,6 +5727,11 @@ static int fg_gen3_probe(struct platform_device *pdev)
 
        device_init_wakeup(chip->dev, true);
        schedule_delayed_work(&chip->profile_load_work, 0);
+       schedule_delayed_work(&chip->soc_work, 0);
+
+       chip->param.batt_soc = -EINVAL;
+       schedule_delayed_work(&chip->soc_monitor_work,
+                       msecs_to_jiffies(MONITOR_SOC_WAIT_MS));
 
        pr_debug("FG GEN3 driver probed successfully\n");
        return 0;
@@ -5486,8 +5780,12 @@ static int fg_gen3_resume(struct device *dev)
 
        spin_lock(&chip->suspend_lock);
        chip->suspended = false;
+       chip->param.update_now = true;
        spin_unlock(&chip->suspend_lock);
 
+       schedule_delayed_work(&chip->soc_monitor_work,
+                       msecs_to_jiffies(MONITOR_SOC_WAIT_MS));
+
        return 0;
 }
 
index 50113a0..98b5ee9 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
- *
+ * Copyright (C) 2019 XiaoMi, Inc.
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
  * only version 2 as published by the Free Software Foundation.
@@ -36,33 +36,21 @@ static struct smb_params v1_params = {
                .name   = "fast charge current",
                .reg    = FAST_CHARGE_CURRENT_CFG_REG,
                .min_u  = 0,
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
                .max_u  = 3300000,
-#else
-               .max_u  = 4500000,
-#endif
                .step_u = 25000,
        },
        .fv                     = {
                .name   = "float voltage",
                .reg    = FLOAT_VOLTAGE_CFG_REG,
                .min_u  = 3487500,
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
                .max_u  = 4400000,
-#else
-               .max_u  = 4920000,
-#endif
                .step_u = 7500,
        },
        .usb_icl                = {
                .name   = "usb input current limit",
                .reg    = USBIN_CURRENT_LIMIT_CFG_REG,
                .min_u  = 0,
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
                .max_u  = 3000000,
-#else
-               .max_u  = 4800000,
-#endif
                .step_u = 25000,
        },
        .icl_stat               = {
@@ -76,11 +64,7 @@ static struct smb_params v1_params = {
                .name   = "usb otg current limit",
                .reg    = OTG_CURRENT_LIMIT_CFG_REG,
                .min_u  = 250000,
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
                .max_u  = 1500000,
-#else
-               .max_u  = 2000000,
-#endif
                .step_u = 250000,
        },
        .dc_icl                 = {
@@ -136,13 +120,16 @@ static struct smb_params v1_params = {
                .name   = "jeita fcc reduction",
                .reg    = JEITA_CCCOMP_CFG_REG,
                .min_u  = 0,
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
                .max_u  = 3000000,
-#else
-               .max_u  = 1575000,
-#endif
                .step_u = 25000,
        },
+       .jeita_fv_comp          = {
+               .name   = "jeita fv reduction",
+               .reg    = JEITA_FVCOMP_CFG_REG,
+               .min_u  = 0,
+               .max_u  = 472500,
+               .step_u = 7500,
+       },
        .freq_buck              = {
                .name   = "buck switching frequency",
                .reg    = CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG,
@@ -186,6 +173,9 @@ struct smb_dt_props {
        struct  device_node *revid_dev_node;
        int     float_option;
        int     chg_inhibit_thr_mv;
+       int     jeita_cool_cc_delta;
+       int     jeita_hot_cc_delta;
+       int     jeita_low_cc_delta;
        bool    no_battery;
        bool    hvdcp_disable;
        bool    auto_recharge_soc;
@@ -199,7 +189,7 @@ struct smb2 {
        bool                    bad_part;
 };
 
-static int __debug_mask;
+static int __debug_mask = PR_OEM | PR_OTG;
 module_param_named(
        debug_mask, __debug_mask, int, S_IRUSR | S_IWUSR
 );
@@ -215,15 +205,17 @@ module_param_named(
 
 #define MICRO_1P5A             1500000
 #define MICRO_P1A              100000
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-#define MAX_DCP_ICL_UA         1800000
-#endif
+#define MAX_DCP_ICL_UA  1800000
 #define OTG_DEFAULT_DEGLITCH_TIME_MS   50
 #define MIN_WD_BARK_TIME               16
 #define DEFAULT_WD_BARK_TIME           64
 #define BITE_WDOG_TIMEOUT_8S           0x3
 #define BARK_WDOG_TIMEOUT_MASK         GENMASK(3, 2)
 #define BARK_WDOG_TIMEOUT_SHIFT                2
+#define DEFAULT_CRITICAL_JEITA_CCOMP 2975000
+#define JEITA_SOFT_HOT_CC_COMP          1600000
+#define JEITA_SOFT_COOL_CC_COMP         2225000
+
 static int smb2_parse_dt(struct smb2 *chip)
 {
        struct smb_charger *chg = &chip->chg;
@@ -264,9 +256,7 @@ static int smb2_parse_dt(struct smb2 *chip)
        if (rc < 0)
                chip->dt.usb_icl_ua = -EINVAL;
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
        chg->dcp_icl_ua = MAX_DCP_ICL_UA;
-#endif
 
        rc = of_property_read_u32(node,
                                "qcom,otg-cl-ua", &chg->otg_cl_ua);
@@ -301,13 +291,12 @@ static int smb2_parse_dt(struct smb2 *chip)
        if (rc < 0)
                chip->dt.wipower_max_uw = -EINVAL;
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
+#ifdef CONFIG_FB
        if (of_find_property(node, "qcom,thermal-mitigation-dcp", &byte_len)) {
-               chg->thermal_mitigation_dcp = devm_kzalloc(chg->dev, byte_len,
-                       GFP_KERNEL);
+               chg->thermal_mitigation_dcp = devm_kzalloc(chg->dev, byte_len, GFP_KERNEL);
 
-               if (chg->thermal_mitigation_dcp == NULL)
-                       return -ENOMEM;
+       if (chg->thermal_mitigation_dcp == NULL)
+               return -ENOMEM;
 
                chg->thermal_levels = byte_len / sizeof(u32);
                rc = of_property_read_u32_array(node,
@@ -317,16 +306,14 @@ static int smb2_parse_dt(struct smb2 *chip)
                if (rc < 0) {
                        dev_err(chg->dev,
                                "Couldn't read threm limits rc = %d\n", rc);
-                       return rc;
+               return rc;
                }
        }
-
        if (of_find_property(node, "qcom,thermal-mitigation-qc3", &byte_len)) {
-               chg->thermal_mitigation_qc3 = devm_kzalloc(chg->dev, byte_len,
-                       GFP_KERNEL);
+               chg->thermal_mitigation_qc3 = devm_kzalloc(chg->dev, byte_len, GFP_KERNEL);
 
-               if (chg->thermal_mitigation_qc3 == NULL)
-                       return -ENOMEM;
+       if (chg->thermal_mitigation_qc3 == NULL)
+               return -ENOMEM;
 
                chg->thermal_levels = byte_len / sizeof(u32);
                rc = of_property_read_u32_array(node,
@@ -335,14 +322,12 @@ static int smb2_parse_dt(struct smb2 *chip)
                                chg->thermal_levels);
                if (rc < 0) {
                        dev_err(chg->dev,
-                               "Couldn't read threm limits rc = %d\n", rc);
-                       return rc;
+                                       "Couldn't read threm limits rc = %d\n", rc);
+               return rc;
                }
        }
-
        if (of_find_property(node, "qcom,thermal-mitigation-qc2", &byte_len)) {
-               chg->thermal_mitigation_qc2 = devm_kzalloc(chg->dev, byte_len,
-                       GFP_KERNEL);
+               chg->thermal_mitigation_qc2 = devm_kzalloc(chg->dev, byte_len, GFP_KERNEL);
 
                if (chg->thermal_mitigation_qc2 == NULL)
                        return -ENOMEM;
@@ -401,10 +386,6 @@ static int smb2_parse_dt(struct smb2 *chip)
 
        chg->micro_usb_mode = of_property_read_bool(node, "qcom,micro-usb");
 
-#ifndef CONFIG_MACH_XIAOMI_MSM8998
-       chg->dcp_icl_ua = chip->dt.usb_icl_ua;
-#endif
-
        chg->suspend_input_on_debug_batt = of_property_read_bool(node,
                                        "qcom,suspend-input-on-debug-batt");
 
@@ -413,9 +394,26 @@ static int smb2_parse_dt(struct smb2 *chip)
        if (rc < 0)
                chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
 
+       rc = of_property_read_u32(node, "qcom,fcc-low-temp-delta",
+                               &chip->dt.jeita_low_cc_delta);
+       if (rc < 0)
+               chip->dt.jeita_low_cc_delta = DEFAULT_CRITICAL_JEITA_CCOMP;
+       chg->jeita_ccomp_low_delta = chip->dt.jeita_low_cc_delta;
+
+       rc = of_property_read_u32(node, "qcom,fcc-hot-temp-delta",
+                               &chip->dt.jeita_hot_cc_delta);
+       if (rc < 0)
+               chip->dt.jeita_hot_cc_delta = JEITA_SOFT_HOT_CC_COMP;
+       chg->jeita_ccomp_hot_delta = chip->dt.jeita_hot_cc_delta;
+
+       rc = of_property_read_u32(node, "qcom,fcc-cool-temp-delta",
+                               &chip->dt.jeita_cool_cc_delta);
+       if (rc < 0)
+               chip->dt.jeita_cool_cc_delta = JEITA_SOFT_COOL_CC_COMP;
+       chg->jeita_ccomp_cool_delta = chip->dt.jeita_cool_cc_delta;
+
        chg->fcc_stepper_mode = of_property_read_bool(node,
                                        "qcom,fcc-stepping-enable");
-
        return 0;
 }
 
@@ -443,10 +441,13 @@ static enum power_supply_property smb2_usb_props[] = {
        POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
        POWER_SUPPLY_PROP_HW_CURRENT_MAX,
        POWER_SUPPLY_PROP_REAL_TYPE,
+       POWER_SUPPLY_PROP_HVDCP3_TYPE,
        POWER_SUPPLY_PROP_PR_SWAP,
        POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
        POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
        POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
+       POWER_SUPPLY_PROP_RERUN_APSD,
+       POWER_SUPPLY_PROP_TYPE_RECHECK,
 };
 
 static int smb2_usb_get_prop(struct power_supply *psy,
@@ -499,6 +500,16 @@ static int smb2_usb_get_prop(struct power_supply *psy,
                else
                        val->intval = chg->real_charger_type;
                break;
+       case POWER_SUPPLY_PROP_HVDCP3_TYPE:
+               if (chg->pd_active)
+                       val->intval = USB_PD;
+               else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP)
+                       val->intval = HVDCP2_TYPE;
+               else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3)
+                       val->intval = HVDCP3_CLASSA_18W;
+               else
+                       val->intval = HVDCP3_NONE;
+               break;
        case POWER_SUPPLY_PROP_TYPEC_MODE:
                if (chg->micro_usb_mode)
                        val->intval = POWER_SUPPLY_TYPEC_NONE;
@@ -562,6 +573,9 @@ static int smb2_usb_get_prop(struct power_supply *psy,
                val->intval = get_client_vote(chg->usb_icl_votable,
                                              USB_PSY_VOTER);
                break;
+       case POWER_SUPPLY_PROP_TYPE_RECHECK:
+               rc = smblib_get_prop_type_recheck(chg, val);
+               break;
        default:
                pr_err("get prop %d is not supported in usb\n", psp);
                rc = -EINVAL;
@@ -623,6 +637,12 @@ static int smb2_usb_set_prop(struct power_supply *psy,
        case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
                rc = smblib_set_prop_sdp_current_max(chg, val);
                break;
+       case POWER_SUPPLY_PROP_RERUN_APSD:
+               rc = smblib_set_prop_rerun_apsd(chg, val);
+               break;
+       case POWER_SUPPLY_PROP_TYPE_RECHECK:
+               rc = smblib_set_prop_type_recheck(chg, val);
+               break;
        default:
                pr_err("set prop %d is not supported\n", psp);
                rc = -EINVAL;
@@ -1027,9 +1047,11 @@ static enum power_supply_property smb2_batt_props[] = {
        POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
        POWER_SUPPLY_PROP_CHARGE_DONE,
        POWER_SUPPLY_PROP_PARALLEL_DISABLE,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
        POWER_SUPPLY_PROP_SET_SHIP_MODE,
        POWER_SUPPLY_PROP_DIE_HEALTH,
        POWER_SUPPLY_PROP_RERUN_AICL,
+       POWER_SUPPLY_PROP_CHARGER_TYPE,
        POWER_SUPPLY_PROP_DP_DM,
        POWER_SUPPLY_PROP_CHARGE_COUNTER,
        POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
@@ -1118,6 +1140,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
                val->intval = get_client_vote(chg->pl_disable_votable,
                                              USER_VOTER);
                break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+               rc = smblib_get_prop_batt_charge_full(chg, val);
+               break;
        case POWER_SUPPLY_PROP_SET_SHIP_MODE:
                /* Not in ship mode as long as device is active */
                val->intval = 0;
@@ -1131,6 +1156,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
        case POWER_SUPPLY_PROP_RERUN_AICL:
                val->intval = 0;
                break;
+       case POWER_SUPPLY_PROP_CHARGER_TYPE:
+               val->intval = chg->real_charger_type;
+               break;
        case POWER_SUPPLY_PROP_CHARGE_COUNTER:
        case POWER_SUPPLY_PROP_CHARGE_FULL:
        case POWER_SUPPLY_PROP_CYCLE_COUNT:
@@ -1461,9 +1489,10 @@ static int smb2_configure_typec(struct smb_charger *chg)
        /*
         * disable Type-C factory mode and stay in Attached.SRC state when VCONN
         * over-current happens
-        */
+       */
        rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
-                       FACTORY_MODE_DETECTION_EN_BIT | VCONN_OC_CFG_BIT, 0);
+                       FACTORY_MODE_DETECTION_EN_BIT
+                        | VCONN_OC_CFG_BIT, 0);
        if (rc < 0) {
                dev_err(chg->dev, "Couldn't configure Type-C rc=%d\n", rc);
                return rc;
@@ -1478,7 +1507,7 @@ static int smb2_configure_typec(struct smb_charger *chg)
                return rc;
        }
 
-       /* disable try.SINK mode and legacy cable IRQs */
+       /* disable try.SINK mode by xiaomi and legacy cable IRQs */
        rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT |
                                TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT |
                                TYPEC_LEGACY_CABLE_INT_EN_BIT, 0);
@@ -1486,6 +1515,7 @@ static int smb2_configure_typec(struct smb_charger *chg)
                dev_err(chg->dev, "Couldn't set Type-C config rc=%d\n", rc);
                return rc;
        }
+
        return rc;
 }
 
@@ -1557,6 +1587,30 @@ static int smb2_disable_typec(struct smb_charger *chg)
        return rc;
 }
 
+static int smb2_init_jeita(struct smb2 *chip)
+{
+       struct smb_charger *chg = &chip->chg;
+       int rc;
+
+       /*set cc compensation to 0.3C*/
+       rc = smblib_set_charge_param(chg, &chg->param.jeita_cc_comp, 2225000);
+       if (rc < 0) {
+               pr_err("Couldn't configure jeita_cc rc = %d\n", rc);
+               return rc;
+       }
+       rc = smblib_set_charge_param(chg, &chg->param.jeita_fv_comp, 300000);
+       if (rc < 0) {
+               pr_err("Couldn't configure jeita_cv rc = %d\n", rc);
+               return rc;
+       }
+       rc = smblib_masked_write(chg, JEITA_EN_CFG_REG,
+                                       JEITA_EN_COLD_SL_FCV_BIT, 0);
+       if (rc < 0)
+               pr_err("Couldn't disable cold_sl_fcv rc=%d\n", rc);
+
+       return 0;
+}
+
 static int smb2_init_hw(struct smb2 *chip)
 {
        struct smb_charger *chg = &chip->chg;
@@ -1593,6 +1647,8 @@ static int smb2_init_hw(struct smb2 *chip)
                chg->param.freq_boost.max_u = chip->dt.max_freq_khz;
        }
 
+       smb2_init_jeita(chip);
+
        /* set a slower soft start setting for OTG */
        rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG2_REG,
                                ENG_SSUPPLY_IVREF_OTG_SS_MASK, OTG_SS_SLOW);
@@ -1653,11 +1709,10 @@ static int smb2_init_hw(struct smb2 *chip)
        vote(chg->hvdcp_enable_votable, MICRO_USB_VOTER,
                        chg->micro_usb_mode, 0);
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
        /* Operate the QC2.0 in 5V/9V mode i.e. Disable 12V */
        rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG,
-                               PULSE_COUNT_QC2P0_12V | PULSE_COUNT_QC2P0_9V,
-                               PULSE_COUNT_QC2P0_9V);
+                                       PULSE_COUNT_QC2P0_12V | PULSE_COUNT_QC2P0_9V,
+                                       PULSE_COUNT_QC2P0_9V);
        if (rc < 0) {
                dev_err(chg->dev,
                        "Couldn't configure QC2.0 to 9V rc=%d\n", rc);
@@ -1665,14 +1720,12 @@ static int smb2_init_hw(struct smb2 *chip)
        }
        /* Operate the QC3.0 to limit vbus to 6.6v*/
        rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG,
-                               PULSE_COUNT_QC3P0_mask,
-                               0x8);
+                                               PULSE_COUNT_QC3P0_mask, 0x8);
        if (rc < 0) {
                dev_err(chg->dev,
                        "Couldn't configure QC3.0 to 6.6V rc=%d\n", rc);
                return rc;
        }
-#endif
 
        /*
         * AICL configuration:
@@ -1680,7 +1733,8 @@ static int smb2_init_hw(struct smb2 *chip)
         */
        rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
                        USBIN_AICL_START_AT_MAX_BIT
-                               | USBIN_AICL_ADC_EN_BIT, 0);
+                               | USBIN_AICL_ADC_EN_BIT
+                               | USBIN_AICL_RERUN_EN_BIT, USBIN_AICL_RERUN_EN_BIT);
        if (rc < 0) {
                dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc);
                return rc;
@@ -1770,6 +1824,14 @@ static int smb2_init_hw(struct smb2 *chip)
                return rc;
        }
 
+       /* set usbin collapse timer*/
+       rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
+                                USBIN_COLLAPSE_SEL_MASK, 0x1);
+       if (rc < 0) {
+               dev_err(chg->dev, "set usbin collapse timer fault rc=%d\n",
+                       rc);
+       }
+
        /* disable h/w autonomous parallel charging control */
        rc = smblib_masked_write(chg, MISC_CFG_REG,
                                 STAT_PARALLEL_1400MA_EN_CFG_BIT, 0);
@@ -2078,7 +2140,7 @@ static struct smb_irq_info smb2_irqs[] = {
 /* USB INPUT IRQs */
        [USBIN_COLLAPSE_IRQ] = {
                .name           = "usbin-collapse",
-               .handler        = smblib_handle_debug,
+               .handler        = smblib_handle_usbin_collapse,
        },
        [USBIN_LT_3P6V_IRQ] = {
                .name           = "usbin-lt-3p6v",
@@ -2176,6 +2238,7 @@ static struct smb_irq_info smb2_irqs[] = {
        [SWITCH_POWER_OK_IRQ] = {
                .name           = "switcher-power-ok",
                .handler        = smblib_handle_switcher_power_ok,
+               .wake           = true,
                .storm_data     = {true, 1000, 8},
        },
 };
@@ -2406,10 +2469,8 @@ static int smb2_probe(struct platform_device *pdev)
        /* set driver data before resources request it */
        platform_set_drvdata(pdev, chip);
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
        /* wakeup init should be done at the beginning of smb2_probe */
        device_init_wakeup(chg->dev, true);
-#endif
 
        rc = smb2_init_vbus_regulator(chip);
        if (rc < 0) {
@@ -2524,17 +2585,15 @@ static int smb2_probe(struct platform_device *pdev)
                pr_err("Couldn't get batt charge type rc=%d\n", rc);
                goto cleanup;
        }
-       batt_charge_type = val.intval;
-
-#ifndef CONFIG_MACH_XIAOMI_MSM8998
-       device_init_wakeup(chg->dev, true);
-#endif
 
+       batt_charge_type = val.intval;
        chg->last_soc = -EINVAL;
 
        pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
                usb_present, chg->real_charger_type,
                batt_present, batt_health, batt_charge_type);
+
+       schedule_delayed_work(&chg->reg_work, 60 * HZ);
        return rc;
 
 cleanup:
@@ -2597,24 +2656,32 @@ static void smb2_shutdown(struct platform_device *pdev)
                                 AUTO_SRC_DETECT_BIT, AUTO_SRC_DETECT_BIT);
 }
 
-static int smb2_resume(struct device *dev)
+#ifdef CONFIG_FB
+static int smblib_suspend(struct device *dev)
+{
+       struct smb2 *chip = dev_get_drvdata(dev);
+       struct smb_charger *chg = &chip->chg;
+
+       cancel_delayed_work(&chg->screen_on_work);
+       chg->checking_in_progress = false;
+
+       return 0;
+}
+
+static int smblib_resume(struct device *dev)
 {
        struct smb2 *chip = dev_get_drvdata(dev);
        struct smb_charger *chg = &chip->chg;
        union power_supply_propval pval = {0, };
        int rc;
 
-       if (!chg->batt_psy)
-               return 0;
-
        rc = smblib_get_prop_batt_capacity(chg, &pval);
-       if (rc < 0) {
+       if (rc < 0)
                pr_err("Couldn't get batt capacity rc=%d\n", rc);
-               return 0;
-       }
 
        if (pval.intval != chg->last_soc) {
-               power_supply_changed(chg->batt_psy);
+               if (chg->batt_psy)
+                       power_supply_changed(chg->batt_psy);
                chg->last_soc = pval.intval;
        }
 
@@ -2622,8 +2689,10 @@ static int smb2_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops smb2_pm_ops = {
-       .resume         = smb2_resume,
+       .suspend        = smblib_suspend,
+       .resume         = smblib_resume,
 };
+#endif
 
 static const struct of_device_id match_table[] = {
        { .compatible = "qcom,qpnp-smb2", },
@@ -2635,7 +2704,9 @@ static struct platform_driver smb2_driver = {
                .name           = "qcom,qpnp-smb2",
                .owner          = THIS_MODULE,
                .of_match_table = match_table,
-               .pm             = &smb2_pm_ops,
+#ifdef CONFIG_FB
+               .pm             = &smb2_pm_ops,
+#endif
        },
        .probe          = smb2_probe,
        .remove         = smb2_remove,
index ff4e1df..46b8dda 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
 #include "step-chg-jeita.h"
 #include "storm-watch.h"
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-#include <linux/fb.h>
-#endif
-
 #ifdef CONFIG_FORCE_FAST_CHARGE
 #include <linux/fastchg.h>
 #endif
                                __func__, ##__VA_ARGS__);       \
        } while (0)
 
+static bool off_charge_flag;
+
+#ifdef CONFIG_FB
+static int smblib_fb_notifier_cb(struct notifier_block *self,
+                               unsigned long event, void *data);
+#endif
+
 static bool is_secure(struct smb_charger *chg, int addr)
 {
        if (addr == SHIP_MODE_REG || addr == FREQ_CLK_DIV_REG)
@@ -115,6 +119,7 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
 {
        int rc, cc_minus_ua;
        u8 stat;
+       union power_supply_propval batt_temp;
 
        rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
        if (rc < 0) {
@@ -123,11 +128,20 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
                return rc;
        }
 
+       smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n", stat);
+
        if (!(stat & BAT_TEMP_STATUS_SOFT_LIMIT_MASK)) {
                *cc_delta_ua = 0;
                return 0;
        }
 
+       rc = smblib_get_prop_from_bms(chg,
+                               POWER_SUPPLY_PROP_TEMP, &batt_temp);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't get batt temp rc=%d\n", rc);
+               return rc;
+       }
+
        rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
                                        &cc_minus_ua);
        if (rc < 0) {
@@ -135,10 +149,64 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
                return rc;
        }
 
+       if ((stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT) == BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT) {
+               if (cc_minus_ua != chg->jeita_ccomp_hot_delta) {
+                       rc = smblib_set_charge_param(chg, &chg->param.jeita_cc_comp,
+                                                       chg->jeita_ccomp_hot_delta);
+                       if (rc < 0)
+                               pr_err("%s: Couldn't configure jeita_cc rc=%d\n", __func__, rc);
+               }
+       } else if ((stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT) == BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT) {
+               if (batt_temp.intval >= 0) {
+                       if (batt_temp.intval <= BATT_TEMP_CRITICAL_LOW) {                /*set 0.1C on 0~5 Degree */
+                               rc = smblib_set_charge_param(chg, &chg->param.jeita_cc_comp,
+                                                               chg->jeita_ccomp_low_delta);
+                       if (rc < 0)
+                               pr_err("%s: Couldn't configure jeita_cc rc=%d\n", __func__, rc);
+                       } else {                                                /*set 0.3C on 5~15 Degree */
+                               rc = smblib_set_charge_param(chg, &chg->param.jeita_cc_comp,
+                                                               chg->jeita_ccomp_cool_delta);
+                               if (rc < 0)
+                                       pr_err("%s: Couldn't configure jeita_cc rc=%d\n", __func__, rc);
+                       }
+               }
+       }
+
+       rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp, &cc_minus_ua);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
+               return rc;
+       }
+
        *cc_delta_ua = -cc_minus_ua;
        return 0;
 }
 
+static void smblib_monitor_low_temp_work(struct work_struct *work)
+{
+       struct smb_charger *chg = container_of(work, struct smb_charger,
+                                               monitor_low_temp_work.work);
+       int rc, jeita_cc_delta_ua;
+       union power_supply_propval batt_temp;
+
+       rc = smblib_get_prop_from_bms(chg,
+                               POWER_SUPPLY_PROP_TEMP, &batt_temp);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't get batt temp rc=%d\n", rc);
+               return;
+       }
+       if (batt_temp.intval >= 0 && batt_temp.intval<= BATT_TEMP_COOL_THR) {      /*set 0.1C on 0~5 Degree */
+               rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
+               if (rc < 0) {
+                       smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
+                       jeita_cc_delta_ua = 0;
+               }
+       }
+       schedule_delayed_work(&chg->monitor_low_temp_work,
+                               msecs_to_jiffies(CHG_MONITOR_WORK_DELAY_MS));
+
+}
+
 int smblib_icl_override(struct smb_charger *chg, bool override)
 {
        int rc;
@@ -277,6 +345,9 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
                        rc);
                return result;
        }
+       smblib_dbg(chg, PR_REGISTER, "APSD_RESULT = 0x%02x\n", stat);
+       pr_info("%s: APSD_RESULT = 0x%02x\n", __func__, stat);
+
        stat &= APSD_RESULT_STATUS_MASK;
 
        for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
@@ -407,6 +478,9 @@ int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
                }
        }
 
+       smblib_err(chg, "%s: write %s to USBIN_SUSPEND_BIT\n", __func__,
+                               suspend ? "suspend" : "resume");
+
        return rc;
 }
 
@@ -456,6 +530,7 @@ static int smblib_set_adapter_allowance(struct smb_charger *chg,
 }
 
 #define MICRO_5V       5000000
+#define MICRO_6V        6000000
 #define MICRO_9V       9000000
 #define MICRO_12V      12000000
 static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
@@ -558,6 +633,133 @@ static void smblib_rerun_apsd(struct smb_charger *chg)
                smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
 }
 
+#define PERIPHERAL_MASK         0xFF
+static u16 peripheral_base;
+static char log[256] = "";
+static char version[8] = "smb:01:";
+static inline void dump_reg(struct smb_charger *chg, u16 addr,
+                                                       const char *name)
+{
+       u8 reg;
+       int rc;
+       char reg_data[50] = "";
+
+       if (NULL == name) {
+               strlcat(log, "\n", sizeof(log));
+               printk(log);
+               return;
+       }
+
+       rc = smblib_read(chg, addr, &reg);
+       if (rc < 0)
+               smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
+       /* print one peripheral base registers in one line */
+       if (peripheral_base != (addr & ~PERIPHERAL_MASK)) {
+               peripheral_base = addr & ~PERIPHERAL_MASK;
+               memset(log, 0, sizeof(log));
+               snprintf(reg_data, sizeof(reg_data), "%s%04x ", version, peripheral_base);
+               strlcat(log, reg_data, sizeof(log));
+       }
+       memset(reg_data, 0, sizeof(reg_data));
+       snprintf(reg_data, sizeof(reg_data), "%02x ", reg);
+       strlcat(log, reg_data, sizeof(log));
+
+       smblib_dbg(chg, PR_REGISTER, "%s - %04X = %02X\n",
+                                                       name, addr, reg);
+}
+
+static void dump_regs(struct smb_charger *chg)
+{
+       u16 addr;
+
+       /* charger peripheral */
+       for (addr = 0x6; addr <= 0xE; addr++)
+               dump_reg(chg, CHGR_BASE + addr, "CHGR Status");
+
+       for (addr = 0x10; addr <= 0x1B; addr++)
+               dump_reg(chg, CHGR_BASE + addr, "CHGR INT");
+
+       for (addr = 0x50; addr <= 0x70; addr++)
+               dump_reg(chg, CHGR_BASE + addr, "CHGR Config");
+
+       dump_reg(chg, CHGR_BASE + addr, NULL);
+
+       for (addr = 0x6; addr <= 0x8; addr++)
+               dump_reg(chg, OTG_BASE + addr, "OTG Status");
+
+       for (addr = 0x9; addr <= 0x1B; addr++)
+               dump_reg(chg, OTG_BASE + addr, "OTG INT");
+
+       for (addr = 0x40; addr <= 0x53; addr++)
+               dump_reg(chg, OTG_BASE + addr, "OTG Config");
+
+       dump_reg(chg, OTG_BASE + addr, NULL);
+
+       for (addr = 0x10; addr <= 0x1B; addr++)
+               dump_reg(chg, BATIF_BASE + addr, "BATIF INT");
+
+       for (addr = 0x50; addr <= 0x52; addr++)
+               dump_reg(chg, BATIF_BASE + addr, "BATIF Config");
+
+       for (addr = 0x60; addr <= 0x62; addr++)
+               dump_reg(chg, BATIF_BASE + addr, "BATIF Config");
+
+       for (addr = 0x70; addr <= 0x71; addr++)
+               dump_reg(chg, BATIF_BASE + addr, "BATIF Config");
+
+       dump_reg(chg, BATIF_BASE + addr, NULL);
+
+       for (addr = 0x6; addr <= 0x10; addr++)
+               dump_reg(chg, USBIN_BASE + addr, "USBIN Status");
+
+       for (addr = 0x12; addr <= 0x19; addr++)
+               dump_reg(chg, USBIN_BASE + addr, "USBIN INT ");
+
+       for (addr = 0x40; addr <= 0x43; addr++)
+               dump_reg(chg, USBIN_BASE + addr, "USBIN Cmd ");
+
+       for (addr = 0x58; addr <= 0x70; addr++)
+               dump_reg(chg, USBIN_BASE + addr, "USBIN Config ");
+
+       for (addr = 0x80; addr <= 0x84; addr++)
+               dump_reg(chg, USBIN_BASE + addr, "USBIN Config ");
+
+       dump_reg(chg, USBIN_BASE + addr, NULL);
+
+       for (addr = 0x6; addr <= 0x10; addr++)
+               dump_reg(chg, MISC_BASE + addr, "MISC Status");
+
+       for (addr = 0x15; addr <= 0x1B; addr++)
+               dump_reg(chg, MISC_BASE + addr, "MISC INT");
+
+       for (addr = 0x51; addr <= 0x62; addr++)
+               dump_reg(chg, MISC_BASE + addr, "MISC Config");
+
+       for (addr = 0x70; addr <= 0x76; addr++)
+               dump_reg(chg, MISC_BASE + addr, "MISC Config");
+
+       for (addr = 0x80; addr <= 0x84; addr++)
+               dump_reg(chg, MISC_BASE + addr, "MISC Config");
+
+       for (addr = 0x90; addr <= 0x94; addr++)
+               dump_reg(chg, MISC_BASE + addr, "MISC Config");
+
+       dump_reg(chg, MISC_BASE + addr, NULL);
+
+       for (addr = 0x10; addr <= 0x1A; addr++)
+               dump_reg(chg, 0x1700 + addr, "PDPHY INT");
+
+       for (addr = 0x40; addr <= 0x48; addr++)
+               dump_reg(chg, 0x1700 + addr, "PDPHY INT");
+
+       for (addr = 0x4A; addr <= 0x4C; addr++)
+               dump_reg(chg, 0x1700 + addr, "PDPHY Config");
+
+       dump_reg(chg, 0x1700 + 0x58, "PDPHY Ctrl");
+
+       dump_reg(chg, 0x1700 + addr, NULL);
+}
+
 static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
 {
        const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
@@ -565,6 +767,7 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
        /* if PD is active, APSD is disabled so won't have a valid result */
        if (chg->pd_active) {
                chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
+               chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
        } else {
                /*
                 * Update real charger type only if its not FLOAT
@@ -572,10 +775,13 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
                 */
                if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
                        chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
-               chg->real_charger_type = apsd_result->pst;
+               {
+                       chg->real_charger_type = apsd_result->pst;
+                       chg->usb_psy_desc.type = apsd_result->pst;
+               }
        }
 
-       smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
+       smblib_dbg(chg, PR_OEM, "APSD=%s PD=%d\n",
                                        apsd_result->name, chg->pd_active);
        return apsd_result;
 }
@@ -679,6 +885,7 @@ static void smblib_uusb_removal(struct smb_charger *chg)
        vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
        vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
        vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0);
+       vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
 
        cancel_delayed_work_sync(&chg->hvdcp_detect_work);
 
@@ -741,6 +948,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg)
 int smblib_rerun_apsd_if_required(struct smb_charger *chg)
 {
        union power_supply_propval val;
+       const struct apsd_result *apsd_result;
        int rc;
 
        rc = smblib_get_prop_usb_present(chg, &val);
@@ -752,13 +960,29 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg)
        if (!val.intval)
                return 0;
 
+       /*
        rc = smblib_request_dpdm(chg, true);
        if (rc < 0)
                smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+       */
 
        chg->uusb_apsd_rerun_done = true;
-       smblib_rerun_apsd(chg);
 
+       if (!off_charge_flag) {
+               rc = smblib_request_dpdm(chg, true);
+               if (rc < 0)
+                       smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+               smblib_rerun_apsd(chg);
+       } else {
+               apsd_result = smblib_update_usb_type(chg);
+               /* if apsd result is SDP and off-charge mode, no need rerun apsd */
+               if (!(apsd_result->bit & SDP_CHARGER_BIT)) {
+                       rc = smblib_request_dpdm(chg, true);
+                       if (rc < 0)
+                               smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+                       smblib_rerun_apsd(chg);
+               }
+       }
        return 0;
 }
 
@@ -907,20 +1131,13 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
 {
        int rc = 0;
        bool override;
-
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
        union power_supply_propval val = {0, };
        int usb_present = 0;
-#endif
 
        /* suspend and return if 25mA or less is requested */
        if (icl_ua < USBIN_25MA)
                return smblib_set_usb_suspend(chg, true);
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
-#endif
-
        if (icl_ua == INT_MAX)
                goto override_suspend_config;
 
@@ -933,21 +1150,16 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
                        goto enable_icl_changed_interrupt;
                }
        } else {
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
                rc = smblib_get_prop_usb_present(chg, &val);
                if (rc < 0)
                        smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
                else
                        usb_present = val.intval;
-
                if (usb_present
                                && chg->typec_mode == POWER_SUPPLY_TYPEC_NONE)
                        set_sdp_current(chg, 500000);
                else
                        set_sdp_current(chg, 100000);
-#else
-               set_sdp_current(chg, 100000);
-#endif
                rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
                if (rc < 0) {
                        smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
@@ -992,11 +1204,6 @@ override_suspend_config:
        }
 
 enable_icl_changed_interrupt:
-
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
-#endif
-
        return rc;
 }
 
@@ -1649,18 +1856,24 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
        stat = stat & BATTERY_CHARGER_STATUS_MASK;
 
        if (!usb_online && !dc_online) {
-               switch (stat) {
-               case TERMINATE_CHARGE:
-               case INHIBIT_CHARGE:
-                       val->intval = POWER_SUPPLY_STATUS_FULL;
-                       break;
-               default:
-                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-                       break;
-               }
+               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
                return rc;
        }
 
+       rc = smblib_get_prop_batt_health(chg, &pval);
+       if (rc < 0)
+               smblib_err(chg, "Couldn't read batt health rc=%d\n", rc);
+
+       /*this is a workaround to support type-c apapter without PD*/
+       smblib_dbg(chg, PR_MISC, "typec_en_dis_active = %d\n", chg->typec_en_dis_active);
+
+       if (chg->typec_en_dis_active && pval.intval != POWER_SUPPLY_HEALTH_OVERHEAT
+                                    && pval.intval != POWER_SUPPLY_HEALTH_COLD)
+       {
+               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               return 0;
+       }
+
        switch (stat) {
        case TRICKLE_CHARGE:
        case PRE_CHARGE:
@@ -1671,7 +1884,13 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
                break;
        case TERMINATE_CHARGE:
        case INHIBIT_CHARGE:
-               val->intval = POWER_SUPPLY_STATUS_FULL;
+               if (POWER_SUPPLY_HEALTH_WARM == pval.intval)
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               else if (POWER_SUPPLY_HEALTH_OVERHEAT == pval.intval
+                                       || pval.intval == POWER_SUPPLY_HEALTH_COLD)
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
                break;
        case DISABLE_CHARGE:
                val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@@ -1681,12 +1900,13 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
                break;
        }
 
-       if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
+       if (val->intval != POWER_SUPPLY_STATUS_CHARGING
+                       || pval.intval == POWER_SUPPLY_HEALTH_WARM)
                return 0;
 
        rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
        if (rc < 0) {
-               smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+               smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_7 rc=%d\n",
                                rc);
                        return rc;
        }
@@ -1819,6 +2039,19 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg,
        return 0;
 }
 
+int smblib_get_prop_batt_charge_full(struct smb_charger *chg,
+                                    union power_supply_propval *val)
+{
+       int rc;
+
+       if (!chg->bms_psy)
+               return -EINVAL;
+
+       rc = power_supply_get_property(chg->bms_psy,
+                                      POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, val);
+       return rc;
+}
+
 int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
                                        union power_supply_propval *val)
 {
@@ -1832,8 +2065,13 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
                return rc;
        }
 
+       pr_info("BATTERY_CHARGER_STATUS_1 = 0x%02x\n", stat);
        stat = stat & BATTERY_CHARGER_STATUS_MASK;
        val->intval = (stat == TERMINATE_CHARGE);
+
+       /* if charge is done, clear the chg_awake_voter */
+       if (val->intval == 1)
+               vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0);
        return 0;
 }
 
@@ -1906,93 +2144,107 @@ int smblib_set_prop_batt_capacity(struct smb_charger *chg,
        return 0;
 }
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-#define SCREEN_ON_ICL          3200000
-#define SCREEN_ON_CHECK_MS     90000
-#define SCREEN_OFF_CHECK_MS    5000
-static void smblib_fb_state_work(struct work_struct *work)
+#ifdef CONFIG_FB
+#define ICL_MINUS       1600000
+static void smblib_screen_on_work(struct work_struct *work)
 {
-       struct smb_charger *chg = container_of(work, struct smb_charger,
-                       fb_state_work.work);
-       union power_supply_propval usb_present;
-       int rc;
+       struct smb_charger *chg = container_of(work,
+                       struct smb_charger, screen_on_work.work);
 
-       rc = smblib_get_prop_usb_present(chg, &usb_present);
+       int rc, usb_present;
+       union power_supply_propval val;
+
+       mutex_lock(&chg->screen_lock);
+       chg->checking_in_progress = false;
+       mutex_unlock(&chg->screen_lock);
+
+       rc = smblib_get_prop_usb_present(chg, &val);
        if (rc < 0) {
-               smblib_err(chg, "Couldn't check usb present, rc=%d\n", rc);
+               pr_err("Couldn't get usb present rc=%d\n", rc);
                return;
        }
+       usb_present = val.intval;
 
-       if (!usb_present.intval)
+       /* if usb is not present , no actions */
+       if (!usb_present)
                return;
 
        if (!chg->usb_icl_votable) {
-               smblib_err(chg, "Couldn't find USB ICL votable\n");
+               pr_err("%s: icl_votable couldn't ready\n", __func__);
                return;
        }
 
+       mutex_lock(&chg->screen_lock);
        if (chg->screen_on) {
-               smblib_dbg(chg, PR_MISC, "Screen is on, lower USB ICL\n");
-               vote(chg->usb_icl_votable, FB_SCREEN_VOTER, true, SCREEN_ON_ICL);
+               pr_info("%s: screen_on set ICL %d mA\n", __func__, ICL_MINUS);
+               vote(chg->usb_icl_votable, FB_SCREEN_VOTER, true, ICL_MINUS);
        } else {
-               smblib_dbg(chg, PR_MISC, "Screen is off, reset USB ICL\n");
+               pr_info("%s: screen_off resume ICL \n", __func__);
                vote(chg->usb_icl_votable, FB_SCREEN_VOTER, false, 0);
        }
+       mutex_unlock(&chg->screen_lock);
 }
 
-static int smblib_fb_state_cb(struct notifier_block *self,
-               unsigned long type, void *data)
+#define SCREEN_ON_CHECK_MS      90000
+#define SCREEN_OFF_CHECK_MS     5000
+static int smblib_fb_notifier_cb(struct notifier_block *self,
+                                       unsigned long event, void *data)
 {
-       struct smb_charger *chg = container_of(self,
-                       struct smb_charger, fb_state_notifier);
        struct fb_event *evdata = data;
-       unsigned int check_ms;
-       unsigned int blank;
-
-       if (!evdata || !evdata->data)
-               goto end;
-
-       if (type != FB_EARLY_EVENT_BLANK)
-               goto end;
-
-       cancel_delayed_work(&chg->fb_state_work);
-
-       blank = *(int *)(evdata->data);
-       switch (blank) {
-       case FB_BLANK_UNBLANK:
-               chg->screen_on = true;
-               check_ms = SCREEN_ON_CHECK_MS;
-               break;
-       case FB_BLANK_POWERDOWN:
-               chg->screen_on = false;
-               check_ms = SCREEN_OFF_CHECK_MS;
-               break;
-       default:
-               goto end;
+       int screen_check_ms;
+       int *blank;
+
+       struct smb_charger *chg =
+                       container_of(self, struct smb_charger, smb_fb_notif);
+
+       mutex_lock(&chg->screen_lock);
+       if (evdata && evdata->data && chg) {
+               if (event == FB_EARLY_EVENT_BLANK) {
+                       blank = evdata->data;
+                       if (*blank == FB_BLANK_UNBLANK) {
+                               chg->screen_on = true;
+                               pr_info("%s: screen_on\n", __func__);
+                               screen_check_ms = SCREEN_ON_CHECK_MS;
+                       } else if (*blank == FB_BLANK_POWERDOWN) {
+                               chg->screen_on = false;
+                               pr_info("%s: screen_off\n", __func__);
+                               screen_check_ms = SCREEN_OFF_CHECK_MS;
+                       }
+                       if (!chg->checking_in_progress &&
+                               ((*blank == FB_BLANK_UNBLANK) ||
+                                       (*blank == FB_BLANK_POWERDOWN))) {
+                               chg->checking_in_progress = true;
+                               schedule_delayed_work(&chg->screen_on_work,
+                                                       msecs_to_jiffies(screen_check_ms));
+                       }
+               }
+       } else {
+               pr_err("%s: Couldn't get fb event\n", __func__);
+               mutex_unlock(&chg->screen_lock);
+               return 0;
        }
-
-       queue_delayed_work(system_power_efficient_wq,
-                       &chg->fb_state_work,
-                       msecs_to_jiffies(check_ms));
-
-end:
-       return NOTIFY_OK;
+       mutex_unlock(&chg->screen_lock);
+       return 0;
 }
 #endif
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-#define MAX_CURRENT_PERCENT            100
-#define HIGH_CURRENT_PERCENT           70
-#define MEDIUM_CURRENT_PERCENT         50
-#endif
 int smblib_set_prop_system_temp_level(struct smb_charger *chg,
                                const union power_supply_propval *val)
 {
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       int *thermal_mitigation;
-       int current_percent;
-       bool throttle_current;
-#endif
+       int rc;
+       union power_supply_propval batt_temp;
+
+       rc = smblib_get_prop_from_bms(chg,
+                               POWER_SUPPLY_PROP_TEMP, &batt_temp);
+       if (rc < 0) {
+               pr_err("Couldn't get batt temp rc=%d\n", rc);
+               return -EINVAL;
+       }
+
+       pr_info("thermal level:%d,batt temp:%d,thermal_levels:%d "
+                       "screen state:%d and chg type:%d\n",
+                       val->intval, batt_temp.intval, chg->thermal_levels,
+                       chg->screen_on, chg->usb_psy_desc.type);
 
        if (val->intval < 0)
                return -EINVAL;
@@ -2005,57 +2257,62 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg,
 
        chg->system_temp_level = val->intval;
        /* disable parallel charge in case of system temp level */
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
        vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
                        (chg->system_temp_level > 2) ? true : false, 0);
-#else
-       vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
-                       chg->system_temp_level ? true : false, 0);
-#endif
 
        if (chg->system_temp_level == chg->thermal_levels)
                return vote(chg->chg_disable_votable,
                        THERMAL_DAEMON_VOTER, true, 0);
 
        vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
-
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       throttle_current = chg->screen_on;
-
        if (chg->system_temp_level == 0)
                return vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, false, 0);
 
-       switch (chg->real_charger_type) {
+#ifdef CONFIG_FB
+       switch (chg->usb_psy_desc.type) {
+       case POWER_SUPPLY_TYPE_USB_DCP:
+               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                               chg->thermal_mitigation_dcp[chg->system_temp_level]);
+               break;
        case POWER_SUPPLY_TYPE_USB_HVDCP:
-               thermal_mitigation = chg->thermal_mitigation_qc2;
+               if (chg->screen_on) {
+                       if (chg->system_temp_level == 6)
+                               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                                       chg->thermal_mitigation_qc2[chg->system_temp_level]);
+                       else if (chg->system_temp_level < 3) {
+                               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                                       (chg->thermal_mitigation_qc2[chg->system_temp_level] * 70 / 100));
+                       } else {
+                               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                                       (chg->thermal_mitigation_qc2[chg->system_temp_level] * 50 / 100)); }
+               } else
+                       vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                               chg->thermal_mitigation_qc2[chg->system_temp_level]);
                break;
        case POWER_SUPPLY_TYPE_USB_HVDCP_3:
-               thermal_mitigation = chg->thermal_mitigation_qc3;
+               if (chg->screen_on) {
+                       if (chg->system_temp_level == 6)
+                               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                                       chg->thermal_mitigation_qc3[chg->system_temp_level]);
+                       else if (chg->system_temp_level < 3) {
+                               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                                       (chg->thermal_mitigation_qc3[chg->system_temp_level] * 70 / 100));
+                       } else {
+                               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                               (chg->thermal_mitigation_qc3[chg->system_temp_level] * 50 / 100)); }
+               } else
+                       vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                               chg->thermal_mitigation_qc3[chg->system_temp_level]);
                break;
-       case POWER_SUPPLY_TYPE_USB_DCP:
        default:
-               thermal_mitigation = chg->thermal_mitigation_dcp;
-               throttle_current = false;
+               vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
+                       chg->thermal_mitigation_dcp[chg->system_temp_level]);
                break;
        }
-
-       if (!throttle_current || chg->system_temp_level == 6)
-               current_percent = MAX_CURRENT_PERCENT;
-       else if (chg->system_temp_level < 3)
-               current_percent = HIGH_CURRENT_PERCENT;
-       else
-               current_percent = MEDIUM_CURRENT_PERCENT;
-
-       vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true,
-                       thermal_mitigation[chg->system_temp_level] * current_percent / 100);
 #else
-       if (chg->system_temp_level == 0)
-               return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
-
        vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
                        chg->thermal_mitigation[chg->system_temp_level]);
 #endif
-
        return 0;
 }
 
@@ -2211,11 +2468,17 @@ int smblib_dp_dm(struct smb_charger *chg, int val)
                        pr_err("Failed to force 5V\n");
                break;
        case POWER_SUPPLY_DP_DM_FORCE_9V:
+               /* donot use qcom hvdcp2.0 mode */
+               return 0;
+               /* Force 1A ICL before requesting higher voltage */
+               vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
                rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
                if (rc < 0)
                        pr_err("Failed to force 9V\n");
                break;
        case POWER_SUPPLY_DP_DM_FORCE_12V:
+               /* Force 1A ICL before requesting higher voltage */
+               vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
                rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
                if (rc < 0)
                        pr_err("Failed to force 12V\n");
@@ -2348,6 +2611,13 @@ int smblib_get_prop_usb_online(struct smb_charger *chg,
                return rc;
        }
 
+       /*smblib_err(chg, "typec_en_dis_active = %d\n", chg->typec_en_dis_active);*/
+
+       if (chg->typec_en_dis_active) {
+               val->intval = 1;
+               return 0;
+       }
+
        rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
        if (rc < 0) {
                smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
@@ -2651,14 +2921,9 @@ int smblib_get_prop_die_health(struct smb_charger *chg,
 
 #define SDP_CURRENT_UA                 500000
 #define CDP_CURRENT_UA                 1500000
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
 #define DCP_CURRENT_UA                 1800000
 #define HVDCP_CURRENT_UA               1500000
-#define HVDCP3_CURRENT_UA              3000000
-#else
-#define DCP_CURRENT_UA                 1500000
-#define HVDCP_CURRENT_UA               3000000
-#endif
+#define HVDCP3_CURRENT_UA               2700000
 #define TYPEC_DEFAULT_CURRENT_UA       900000
 #define TYPEC_MEDIUM_CURRENT_UA                1500000
 #define TYPEC_HIGH_CURRENT_UA          3000000
@@ -2697,6 +2962,7 @@ int smblib_set_prop_pd_current_max(struct smb_charger *chg,
        return rc;
 }
 
+#define FLOAT_CHARGER_UA       1000000
 static int smblib_handle_usb_current(struct smb_charger *chg,
                                        int usb_current)
 {
@@ -2710,6 +2976,7 @@ static int smblib_handle_usb_current(struct smb_charger *chg,
                         */
                        typec_mode = smblib_get_prop_typec_mode(chg);
                        rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+                       rp_ua = FLOAT_CHARGER_UA;
                        rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
                                                                true, rp_ua);
                        if (rc < 0)
@@ -2721,6 +2988,7 @@ static int smblib_handle_usb_current(struct smb_charger *chg,
                         * real_charger_type
                         */
                        chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
+                       chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB;
                        rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
                                                true, usb_current);
                        if (rc < 0)
@@ -2756,6 +3024,42 @@ int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
        return rc;
 }
 
+int smblib_set_prop_rerun_apsd(struct smb_charger *chg,
+                                                               const union power_supply_propval *val)
+{
+       if (val->intval == 1) {
+               chg->float_rerun_apsd = true;
+               smblib_rerun_apsd(chg);
+       }
+       return 0;
+}
+
+int smblib_get_prop_type_recheck(struct smb_charger *chg,
+                                                               union power_supply_propval *val)
+{
+       int status = 0;
+
+       if (chg->recheck_charger)
+               status |= BIT(0) << 8;
+
+       status |= chg->precheck_charger_type << 4;
+       status |= chg->real_charger_type;
+
+       val->intval = status;
+
+       return 0;
+}
+
+int smblib_set_prop_type_recheck(struct smb_charger *chg,
+                                                               const union power_supply_propval *val)
+{
+       if (val->intval == 0) {
+               cancel_delayed_work_sync(&chg->charger_type_recheck);
+               chg->recheck_charger = false;
+       }
+       return 0;
+}
+
 int smblib_set_prop_boost_current(struct smb_charger *chg,
                                    const union power_supply_propval *val)
 {
@@ -3232,8 +3536,7 @@ int smblib_get_charge_current(struct smb_charger *chg,
 
        typec_source_rd = smblib_get_prop_ufp_mode(chg);
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       /* QC 2.0 adapter*/
+       /* QC 2.0 adapter */
        if (apsd_result->bit & QC_2P0_BIT) {
                *total_current_ua = HVDCP_CURRENT_UA;
                return 0;
@@ -3244,13 +3547,6 @@ int smblib_get_charge_current(struct smb_charger *chg,
                *total_current_ua = HVDCP3_CURRENT_UA;
                return 0;
        }
-#else
-       /* QC 2.0/3.0 adapter */
-       if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
-               *total_current_ua = HVDCP_CURRENT_UA;
-               return 0;
-       }
-#endif
 
        if (non_compliant) {
                switch (apsd_result->bit) {
@@ -3367,7 +3663,7 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
        u8 stat;
        int rc;
 
-       smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+       smblib_dbg(chg, PR_OEM, "IRQ: %s\n", irq_data->name);
 
        rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
        if (rc < 0) {
@@ -3394,6 +3690,7 @@ irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
                return IRQ_HANDLED;
        }
 
+       smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
        rerun_election(chg->fcc_votable);
        power_supply_changed(chg->batt_psy);
        return IRQ_HANDLED;
@@ -3419,13 +3716,22 @@ irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+irqreturn_t smblib_handle_usbin_collapse(int irq, void *data)
+{
+       struct smb_irq_data *irq_data = data;
+       struct smb_charger *chg = irq_data->parent_data;
+
+       smblib_dbg(chg, PR_OEM, "IRQ: %s\n", irq_data->name);
+       return IRQ_HANDLED;
+}
+
 irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
 {
        struct smb_irq_data *irq_data = data;
        struct smb_charger *chg = irq_data->parent_data;
        struct storm_watch *wdata;
 
-       smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+       smblib_dbg(chg, PR_OEM, "IRQ: %s\n", irq_data->name);
        if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
                return IRQ_HANDLED;
 
@@ -3434,6 +3740,81 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static void smblib_cc_float_charge_work(struct work_struct *work)
+{
+       union power_supply_propval val = {0, };
+       int rc, usb_present = 0;
+
+       struct smb_charger *chg = container_of(work, struct smb_charger,
+                                       cc_float_charge_work.work);
+
+       rc = smblib_get_prop_usb_present(chg, &val);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
+               return;
+       }
+
+       usb_present = val.intval;
+       /*
+        * if CC pin of C to A cable is not connected to the receptacle
+        * or CC pin is bad or C to C cable CC line is float, vote 500mA and
+        * report charger type as DCP to improve user experience
+        */
+       if (usb_present
+                       && (chg->typec_mode == POWER_SUPPLY_TYPEC_NONE)
+                       && (chg->cc_float_detected == false)) {
+               chg->cc_float_detected = true;
+               chg->real_charger_type = POWER_SUPPLY_TYPE_USB_DCP;
+               chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP;
+               vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
+               vote(chg->usb_icl_votable, CC_FLOAT_VOTER, true, 500000);
+               power_supply_changed(chg->batt_psy);
+       }
+}
+
+static void smblib_check_vbus_work(struct work_struct *work)
+{
+       union power_supply_propval val = {0, };
+       int rc, usb_present = 0;
+
+       struct smb_charger *chg = container_of(work, struct smb_charger,
+                                               check_vbus_work.work);
+
+       rc = smblib_get_prop_usb_present(chg, &val);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
+               return;
+       }
+
+       usb_present = val.intval;
+       if (usb_present) {
+               if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+                       rc = smblib_get_prop_usb_voltage_now(chg, &val);
+                       if (rc < 0)
+                               pr_err("Couldn't get usb voltage rc=%d\n", rc);
+                       pr_info("VBUS now is %d\n", val.intval);
+                       if (val.intval >= QC2_HVDCP_VOL_UV_THR) {
+                               pr_info("this is a normal QC2.0 charger\n");
+                               /* if use usbmid charging, enable hardware INOV again */
+                               vote(chg->hvdcp_hw_inov_dis_votable,
+                                               UNSTANDARD_QC2_VOTER, false, 0);
+                       } else {
+                               pr_info("set adapter allowance to 5V and force 5V charge\n");
+                               rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
+                                               FORCE_5V_BIT, FORCE_5V_BIT);
+                               if (rc < 0)
+                                       smblib_err(chg,
+                                                       "Couldn't force 5V HVDCP rc=%d\n", rc);
+                               smblib_set_usb_pd_allowed_voltage(chg, MICRO_5V, MICRO_5V);
+                               chg->unstandard_hvdcp = true;
+                               vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
+                               vote(chg->usb_icl_votable, UNSTANDARD_QC2_VOTER,
+                                                       true, UNSTANDARD_HVDCP2_UA);
+                       }
+               }
+       }
+}
+
 static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
 {
        if (vbus_rising) {
@@ -3479,10 +3860,18 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
                                                false, 0);
                        }
                }
+               if (chg->cc_float_detected) {
+                       chg->cc_float_detected = false;
+                       chg->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+                       chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
+               }
+               vote(chg->usb_icl_votable, CC_FLOAT_VOTER, false, 0);
+               vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0);
+               cancel_delayed_work_sync(&chg->charger_type_recheck);
        }
 
        power_supply_changed(chg->usb_psy);
-       smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+       smblib_dbg(chg, PR_OEM, "IRQ: usbin-plugin %s\n",
                                        vbus_rising ? "attached" : "detached");
 }
 
@@ -3509,13 +3898,37 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
                rc = smblib_request_dpdm(chg, true);
                if (rc < 0)
                        smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+               vote(chg->awake_votable, CHG_AWAKE_VOTER, true, 0);
+
                if (chg->fcc_stepper_mode)
                        vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0);
+               if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) != 0) {
+                       rc = smblib_set_usb_suspend(chg, false);
+                       if (rc < 0)
+                               smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
+               }
+               if (is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER)) {
+                       rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+                        if (rc < 0)
+                               smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
+               }
+
                /* Schedule work to enable parallel charger */
                vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
                schedule_delayed_work(&chg->pl_enable_work,
                                        msecs_to_jiffies(PL_DELAY_MS));
+               schedule_delayed_work(&chg->monitor_low_temp_work,
+                               msecs_to_jiffies(CHG_MONITOR_WORK_DELAY_MS));
+/*
+               schedule_delayed_work(&chg->cc_float_charge_work,
+                                       msecs_to_jiffies(CC_FLOAT_WORK_START_DELAY_MS));
+*/
+               schedule_delayed_work(&chg->typec_reenable_work,
+                                       msecs_to_jiffies(300));
        } else {
+               cancel_delayed_work_sync(&chg->charger_type_recheck);
+               cancel_delayed_work_sync(&chg->typec_reenable_work);
+
                if (chg->wa_flags & BOOST_BACK_WA) {
                        data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
                        if (data) {
@@ -3537,13 +3950,23 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
                rc = smblib_request_dpdm(chg, false);
                if (rc < 0)
                        smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+               vote(chg->usb_icl_votable, CC_FLOAT_VOTER, false, 0);
+                if (chg->cc_float_detected) {
+                        chg->cc_float_detected = false;
+                        chg->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+                        chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
+                }
+               chg->recheck_charger = false;
+               chg->legacy = false;
+               chg->precheck_charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+               vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0);
        }
 
        if (chg->micro_usb_mode)
                smblib_micro_usb_plugin(chg, vbus_rising);
 
        power_supply_changed(chg->usb_psy);
-       smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+       smblib_dbg(chg, PR_OEM, "IRQ: usbin-plugin %s\n",
                                        vbus_rising ? "attached" : "detached");
 }
 
@@ -3651,6 +4074,12 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
        smblib_check_ov_condition(chg);
        power_supply_changed(chg->usb_main_psy);
        if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+               /* if unstandard hvdcp is detected, set opt freq to 5V freq */
+               if (chg->unstandard_hvdcp) {
+                       smblib_set_opt_freq_buck(chg,
+                                               chg->chg_freq.freq_5V);
+                       return;
+               }
                rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
                if (rc < 0) {
                        smblib_err(chg,
@@ -3666,10 +4095,12 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
                case QC_9V_BIT:
                        smblib_set_opt_freq_buck(chg,
                                        chg->chg_freq.freq_9V);
+                       vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
                        break;
                case QC_12V_BIT:
                        smblib_set_opt_freq_buck(chg,
                                        chg->chg_freq.freq_12V);
+                       vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
                        break;
                default:
                        smblib_set_opt_freq_buck(chg,
@@ -3706,10 +4137,8 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
                                              bool rising)
 {
        const struct apsd_result *apsd_result;
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       int current_ua;
-#endif
        int rc;
+       int current_ua;
 
        if (!rising)
                return;
@@ -3732,30 +4161,41 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
 
        /* the APSD done handler will set the USB supply type */
        apsd_result = smblib_get_apsd_result(chg);
-       if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
+
                if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
-                       /* force HVDCP2 to 9V if INOV is disabled */
-                       rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
-                                       FORCE_9V_BIT, FORCE_9V_BIT);
-                       if (rc < 0)
-                               smblib_err(chg,
-                                       "Couldn't force 9V HVDCP rc=%d\n", rc);
+                       /* disable hardware INOV and force HVDCP2 to 9V */
+                       if (!chg->check_vbus_once) {
+                               vote(chg->hvdcp_hw_inov_dis_votable,
+                                               UNSTANDARD_QC2_VOTER, true, 0);
+                               /* force HVDCP2 to 9V if INOV is disabled */
+                               rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
+                                               FORCE_9V_BIT, FORCE_9V_BIT);
+                               if (rc < 0)
+                                       smblib_err(chg,
+                                                       "Couldn't force 9V HVDCP rc=%d\n", rc);
+                       }
                }
-       }
 
-       smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
-                  apsd_result->name);
-
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
        if (apsd_result->bit & QC_2P0_BIT) {
-               current_ua = HVDCP_CURRENT_UA;
+               if (!chg->unstandard_hvdcp)
+                       current_ua = HVDCP_CURRENT_UA;
+               else
+                       current_ua = DCP_CURRENT_UA;
+
+               if (!chg->check_vbus_once) {
+                       schedule_delayed_work(&chg->check_vbus_work,
+                               msecs_to_jiffies(CHECK_VBUS_WORK_DELAY_MS));
+                       chg->check_vbus_once = true;
+               }
        } else if (apsd_result->bit & QC_3P0_BIT) {
                current_ua = HVDCP3_CURRENT_UA;
        }
 
        vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true,
                        current_ua);
-#endif
+
+       smblib_dbg(chg, PR_OEM, "rising; %s detected and current was %d\n",
+                                       apsd_result->name, current_ua);
 }
 
 static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
@@ -3809,10 +4249,8 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
 
 static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
 {
-#ifndef CONFIG_MACH_XIAOMI_MSM8998
        int typec_mode;
        int rp_ua;
-#endif
 
        /* while PD is active it should have complete ICL control */
        if (chg->pd_active)
@@ -3827,40 +4265,30 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
                 */
                if (!is_client_vote_enabled(chg->usb_icl_votable,
                                                                USB_PSY_VOTER))
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
                        vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 500000);
-#else
-
-                       vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
-#endif
                vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
                break;
        case POWER_SUPPLY_TYPE_USB_CDP:
                vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
                break;
        case POWER_SUPPLY_TYPE_USB_DCP:
-#ifndef CONFIG_MACH_XIAOMI_MSM8998
                typec_mode = smblib_get_prop_typec_mode(chg);
                rp_ua = get_rp_based_dcp_current(chg, typec_mode);
                vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
                break;
-#endif
        case POWER_SUPPLY_TYPE_USB_FLOAT:
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-               vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1800000);
-#else
                /*
                 * limit ICL to 100mA, the USB driver will enumerate to check
                 * if this is a SDP and appropriately set the current
                 */
-               vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
-#endif
+               if (chg->recheck_charger)
+                       vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1000000);
+               else
+                       vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
                break;
        case POWER_SUPPLY_TYPE_USB_HVDCP:
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-               vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+               vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
                break;
-#endif
        case POWER_SUPPLY_TYPE_USB_HVDCP_3:
                vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
                break;
@@ -3901,11 +4329,23 @@ static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
 {
        const struct apsd_result *apsd_result;
+       union power_supply_propval pval = {0, };
+       int usb_present = 0, ret = 0;
+
+#ifdef CONFIG_FB
+       union power_supply_propval val = {0, };
+       int rc = 0;
+#endif
 
        if (!rising)
                return;
 
        apsd_result = smblib_update_usb_type(chg);
+       if (is_client_vote_enabled(chg->usb_icl_votable,
+                                                       CC_FLOAT_VOTER)) {
+               if (chg->typec_mode != POWER_SUPPLY_TYPEC_NONE)
+                       vote(chg->usb_icl_votable, CC_FLOAT_VOTER, false, 0);
+       }
 
        if (!chg->typec_legacy_valid)
                smblib_force_legacy_icl(chg, apsd_result->pst);
@@ -3923,6 +4363,9 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
                /* if not DCP then no hvdcp timeout happens, Enable pd here. */
                vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
                                false, 0);
+               /* if floated charger is detected, and audio accessory set icl to 500 */
+               if (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER)
+                       vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
                break;
        case DCP_CHARGER_BIT:
                if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
@@ -3933,6 +4376,34 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
                break;
        }
 
+       if (chg->float_rerun_apsd) {
+               ret = smblib_get_prop_usb_present(chg, &pval);
+               if (ret < 0) {
+                       smblib_err(chg, "Couldn't get usb present ret = %d\n", ret);
+                       return;
+               }
+               usb_present = pval.intval;
+               if (!usb_present)
+                       return;
+               if (apsd_result->bit & QC_2P0_BIT) {
+                       pval.intval = 0;
+                       smblib_set_prop_pd_active(chg, &pval);
+                       chg->float_rerun_apsd = false;
+               } else if (apsd_result->bit & FLOAT_CHARGER_BIT) {
+                       vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1000000);
+                       chg->float_rerun_apsd = false;
+               }
+       }
+
+#ifdef CONFIG_FB
+       val.intval = chg->system_temp_level;
+       rc = power_supply_set_property(chg->batt_psy, POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, &val);
+       if (rc < 0) {
+               smblib_err(chg, "Could not set charger control limit =%d\n", rc);
+               return;
+       }
+#endif
+
        smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
                   apsd_result->name);
 }
@@ -4201,6 +4672,8 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
 
        cancel_delayed_work_sync(&chg->pl_enable_work);
        cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+       cancel_delayed_work_sync(&chg->monitor_low_temp_work);
+       cancel_delayed_work_sync(&chg->check_vbus_work);
 
        /* reset input current limit voters */
        vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
@@ -4209,16 +4682,21 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
        vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
        vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
        vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
+       vote(chg->usb_icl_votable, CC_FLOAT_VOTER, false, 0);
+       vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
+       vote(chg->usb_icl_votable, UNSTANDARD_QC2_VOTER, false, 0);
 
        /* reset hvdcp voters */
        vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
        vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
        vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0);
+       vote(chg->hvdcp_hw_inov_dis_votable, UNSTANDARD_QC2_VOTER, false, 0);
 
        /* reset power delivery voters */
        vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
        vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
        vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
+       vote(chg->hvdcp_hw_inov_dis_votable, UNSTANDARD_QC2_VOTER, false, 0);
 
        /* reset usb irq voters */
        vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
@@ -4229,6 +4707,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
        vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
        vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
        vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+       vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0);
 
        vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
        chg->vconn_attempts = 0;
@@ -4240,6 +4719,10 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
        chg->pd_active = 0;
        chg->pd_hard_reset = 0;
        chg->typec_legacy_valid = false;
+       chg->cc_float_detected = false;
+       chg->float_rerun_apsd = false;
+       chg->check_vbus_once = false;
+       chg->unstandard_hvdcp = false;
 
        /* write back the default FLOAT charger configuration */
        rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
@@ -4317,6 +4800,7 @@ unlock:
        typec_sink_removal(chg);
        smblib_update_usb_type(chg);
 
+       smblib_dbg(chg, PR_OEM, "done\n");
        if (chg->use_extcon) {
                if (chg->otg_present)
                        smblib_notify_usb_host(chg, false);
@@ -4400,15 +4884,20 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
 
        chg->typec_mode = typec_mode;
 
+       cancel_delayed_work_sync(&chg->typec_reenable_work);
+       cancel_delayed_work_sync(&chg->cc_float_charge_work);
+
        if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
                chg->typec_present = true;
-               smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
+               smblib_dbg(chg, PR_OEM, "TypeC %s insertion\n",
                        smblib_typec_mode_name[chg->typec_mode]);
                smblib_handle_typec_insertion(chg);
+               schedule_delayed_work(&chg->charger_type_recheck, msecs_to_jiffies(20000));
        } else if (chg->typec_present &&
                                chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+               cancel_delayed_work_sync(&chg->charger_type_recheck);
                chg->typec_present = false;
-               smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+               smblib_dbg(chg, PR_OEM, "TypeC removal\n");
                smblib_handle_typec_removal(chg);
        }
 
@@ -4452,9 +4941,11 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
                return IRQ_HANDLED;
        }
 
+       smblib_dbg(chg, PR_OEM, "enter\n");
+
        if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
                                         chg->try_sink_active) {
-               smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n",
+               smblib_dbg(chg, PR_OEM, "Ignoring since %s active\n",
                        chg->cc2_detach_wa_active ?
                        "cc2_detach_wa" : "typec_en_dis");
                return IRQ_HANDLED;
@@ -4946,6 +5437,103 @@ static void smblib_pl_enable_work(struct work_struct *work)
        vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
 }
 
+#define CHARGING_PERIOD_S 500
+#define NOT_CHARGING_PERIOD_S 1800
+static void smblib_reg_work(struct work_struct *work)
+{
+       struct smb_charger *chg = container_of(work, struct smb_charger,
+                                                       reg_work.work);
+       int rc, usb_present;
+       union power_supply_propval val;
+       int icl_settle, usb_cur_in, usb_vol_in, charger_temp;
+       int main_fcc, parallel_fcc, parallel_charging_enable, connector_health;
+       int charge_type, typec_mode, typec_orientation;
+
+       dump_regs(chg);
+       rc = smblib_get_prop_usb_present(chg, &val);
+       if (rc < 0) {
+               pr_err("Couldn't get usb present rc=%d\n", rc);
+               schedule_delayed_work(&chg->reg_work,
+                                       NOT_CHARGING_PERIOD_S * HZ);
+               return;
+       }
+       usb_present = val.intval;
+
+       if (usb_present) {
+               smblib_dbg(chg, PR_OEM, "ICL vote value is %d voted by %s\n",
+                                       get_effective_result(chg->usb_icl_votable),
+                                       get_effective_client(chg->usb_icl_votable));
+               smblib_dbg(chg, PR_OEM, "FCC vote value is %d voted by %s\n",
+                                       get_effective_result(chg->fcc_votable),
+                                       get_effective_client(chg->fcc_votable));
+               smblib_dbg(chg, PR_OEM, "FV vote value is %d voted by %s\n",
+                                       get_effective_result(chg->fv_votable),
+                                       get_effective_client(chg->fv_votable));
+
+               power_supply_get_property(chg->usb_psy,
+                                               POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, &val);
+               usb_cur_in = val.intval;
+
+               power_supply_get_property(chg->usb_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
+               usb_vol_in = val.intval;
+
+               power_supply_get_property(chg->usb_psy,
+                                               POWER_SUPPLY_PROP_CURRENT_MAX, &val);
+               icl_settle = val.intval;
+
+               power_supply_get_property(chg->usb_psy,
+                                               POWER_SUPPLY_PROP_REAL_TYPE, &val);
+               charge_type = val.intval;
+
+               power_supply_get_property(chg->batt_psy,
+                                               POWER_SUPPLY_PROP_CHARGER_TEMP, &val);
+               charger_temp = val.intval;
+
+               power_supply_get_property(chg->usb_psy,
+                                               POWER_SUPPLY_PROP_TYPEC_MODE, &val);
+               typec_mode = val.intval;
+
+               power_supply_get_property(chg->usb_psy,
+                                               POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, &val);
+               typec_orientation = val.intval;
+
+               smblib_dbg(chg, PR_OEM, "ICL settle value[%d], Charger_temp[%d], usbin adc current[%d], vbusin adc vol[%d]\n",
+                                       icl_settle, charger_temp, usb_cur_in, usb_vol_in);
+
+               if (!chg->usb_main_psy) {
+                       chg->usb_main_psy = power_supply_get_by_name("main");
+               } else {
+                       power_supply_get_property(chg->usb_main_psy,
+                                                       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &val);
+                       main_fcc = val.intval;
+                       smblib_dbg(chg, PR_OEM, "Main FCC[%d] ", main_fcc);
+               }
+
+               if (!chg->pl.psy) {
+                       chg->pl.psy = power_supply_get_by_name("parallel");
+               } else {
+                       power_supply_get_property(chg->pl.psy,
+                                                       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &val);
+                       parallel_fcc = val.intval;
+                       power_supply_get_property(chg->pl.psy,
+                                                       POWER_SUPPLY_PROP_INPUT_SUSPEND, &val);
+                       parallel_charging_enable = !val.intval;
+                       power_supply_get_property(chg->pl.psy,
+                                                       POWER_SUPPLY_PROP_CONNECTOR_HEALTH, &val);
+                       connector_health = val.intval;
+                       smblib_dbg(chg, PR_OEM, "parallel ENABLE[%d] FCC[%d] CONNECTOR_HEALTH[%d]\n",
+                                       parallel_charging_enable, parallel_fcc, connector_health);
+               }
+
+               smblib_dbg(chg, PR_OEM, "Type-C orientation[%d], Type-C mode[%d], Real Charge Type[%d]\n",
+                                       typec_orientation, typec_mode, charge_type);
+
+               schedule_delayed_work(&chg->reg_work, CHARGING_PERIOD_S * HZ);
+       }
+       else
+               schedule_delayed_work(&chg->reg_work, NOT_CHARGING_PERIOD_S * HZ);
+}
+
 static void smblib_legacy_detection_work(struct work_struct *work)
 {
        struct smb_charger *chg = container_of(work, struct smb_charger,
@@ -4956,7 +5544,7 @@ static void smblib_legacy_detection_work(struct work_struct *work)
 
        mutex_lock(&chg->lock);
        chg->typec_en_dis_active = 1;
-       smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
+       smblib_dbg(chg, PR_OEM, "running legacy unknown workaround\n");
        rc = smblib_masked_write(chg,
                                TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
                                TYPEC_DISABLE_CMD_BIT,
@@ -4976,11 +5564,7 @@ static void smblib_legacy_detection_work(struct work_struct *work)
                smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
 
        /* wait for type-c detection to complete */
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       msleep(1000);
-#else
        msleep(400);
-#endif
 
        rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
        if (rc < 0) {
@@ -4992,7 +5576,8 @@ static void smblib_legacy_detection_work(struct work_struct *work)
        vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
        legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
        rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
-       smblib_dbg(chg, PR_MISC, "legacy workaround done legacy = %d rp_high = %d\n",
+       chg->legacy = legacy;
+       smblib_dbg(chg, PR_OEM, "legacy workaround done legacy = %d rp_high = %d\n",
                        legacy, rp_high);
        if (!legacy || !rp_high)
                vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
@@ -5004,6 +5589,118 @@ unlock:
        mutex_unlock(&chg->lock);
 }
 
+static void smblib_typec_reenable_work(struct work_struct *work)
+{
+       struct smb_charger *chg = container_of(work, struct smb_charger,
+                                                       typec_reenable_work.work);
+       int rc;
+       u8 stat;
+
+       if (chg->pr_swap_in_progress || chg->pd_hard_reset)
+               return;
+
+       mutex_lock(&chg->lock);
+
+       rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
+               goto unlock;
+       }
+
+
+       if (stat == TYPEC_VBUS_STATUS_BIT) {
+               smblib_dbg(chg, PR_OEM, "running typec reenable workaround\n");
+       rc = smblib_masked_write(chg,
+                               TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+                               TYPEC_DISABLE_CMD_BIT,
+                               TYPEC_DISABLE_CMD_BIT);
+       if (rc < 0)
+               smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
+
+       msleep(200);
+
+       rc = smblib_masked_write(chg,
+                               TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+                               TYPEC_DISABLE_CMD_BIT, 0);
+       if (rc < 0)
+               smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
+
+       /* wait for type-c detection to complete */
+
+       }
+
+unlock:
+
+       mutex_unlock(&chg->lock);
+
+       schedule_delayed_work(&chg->cc_float_charge_work,
+                                       msecs_to_jiffies(200));
+
+}
+
+#define TYPE_RECHECK_TIME_20S   20000
+#define TYPE_RECHECK_TIME_5S    5000
+#define TYPE_RECHECK_COUNT      3
+
+static void smblib_charger_type_recheck(struct work_struct *work)
+{
+       struct smb_charger *chg = container_of(work, struct smb_charger,
+                                                                       charger_type_recheck.work);
+       int rc, hvdcp;
+       u8 stat;
+       int recheck_time = TYPE_RECHECK_TIME_5S;
+       static int last_charger_type, check_count;
+
+       smblib_dbg(chg, PR_OEM, "typec_mode:%d,last:%d:real:%d\n",
+                               chg->typec_mode, last_charger_type, chg->real_charger_type);
+
+       if (last_charger_type != chg->real_charger_type)
+               check_count--;
+       last_charger_type = chg->real_charger_type;
+
+       if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3 ||
+                               chg->pd_active || (check_count >= TYPE_RECHECK_COUNT) ||
+                               chg->check_vbus_once ||
+                               ((chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) &&
+                               (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER))) {
+               smblib_dbg(chg, PR_MISC, "hvdcp detect or check_count = %d break\n",
+                                               check_count);
+               check_count = 0;
+               return;
+       }
+
+       if (chg->typec_mode == POWER_SUPPLY_TYPEC_NONE)
+               goto check_next;
+
+       if (!chg->recheck_charger)
+               chg->precheck_charger_type = chg->real_charger_type;
+       chg->recheck_charger = true;
+
+       /* disable APSD CC trigger since CC is attached */
+       rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
+       if (rc < 0)
+               smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", rc);
+
+       rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
+               return;
+       }
+       hvdcp = stat & QC_CHARGER_BIT;
+       smblib_dbg(chg, PR_OEM, "hvdcp:%d chg->legacy:%d check_count:%d\n",
+                                       hvdcp, chg->legacy, check_count);
+
+       if (hvdcp && !chg->legacy) {
+               recheck_time = TYPE_RECHECK_TIME_20S;
+               __smblib_set_prop_pd_active(chg, 0);
+       } else
+               smblib_rerun_apsd_if_required(chg);
+
+check_next:
+       check_count++;
+       schedule_delayed_work(&chg->charger_type_recheck, msecs_to_jiffies(recheck_time));
+}
+
 static int smblib_create_votables(struct smb_charger *chg)
 {
        int rc = 0;
@@ -5198,6 +5895,9 @@ int smblib_init(struct smb_charger *chg)
        mutex_init(&chg->lock);
        mutex_init(&chg->write_lock);
        mutex_init(&chg->otg_oc_lock);
+#ifdef CONFIG_FB
+       mutex_init(&chg->screen_lock);
+#endif
        mutex_init(&chg->vconn_oc_lock);
        INIT_WORK(&chg->bms_update_work, bms_update_work);
        INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
@@ -5206,15 +5906,17 @@ int smblib_init(struct smb_charger *chg)
        INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
        INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
        INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
+       INIT_DELAYED_WORK(&chg->reg_work, smblib_reg_work);
        INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
        INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
        INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
        INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
        INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       INIT_DELAYED_WORK(&chg->fb_state_work, smblib_fb_state_work);
-#endif
-
+       INIT_DELAYED_WORK(&chg->monitor_low_temp_work, smblib_monitor_low_temp_work);
+       INIT_DELAYED_WORK(&chg->cc_float_charge_work, smblib_cc_float_charge_work);
+       INIT_DELAYED_WORK(&chg->typec_reenable_work, smblib_typec_reenable_work);
+       INIT_DELAYED_WORK(&chg->charger_type_recheck, smblib_charger_type_recheck);
+       INIT_DELAYED_WORK(&chg->check_vbus_work, smblib_check_vbus_work);
        chg->fake_capacity = -EINVAL;
        chg->fake_input_current_limited = -EINVAL;
 
@@ -5249,18 +5951,22 @@ int smblib_init(struct smb_charger *chg)
                        return rc;
                }
 
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-               chg->fb_state_notifier.notifier_call = smblib_fb_state_cb;
-               rc = fb_register_client(&chg->fb_state_notifier);
-               if (rc < 0) {
-                       smblib_err(chg,
-                               "Couldn't register notifier rc=%d\n", rc);
-                       return rc;
-               }
-#endif
-
                chg->bms_psy = power_supply_get_by_name("bms");
                chg->pl.psy = power_supply_get_by_name("parallel");
+#ifdef CONFIG_FB
+               if (&chg->smb_fb_notif) {
+                               chg->checking_in_progress = false;
+                               chg->smb_fb_notif.notifier_call = smblib_fb_notifier_cb;
+                               rc = fb_register_client(&chg->smb_fb_notif);
+                       if (rc < 0) {
+                               smblib_err(chg,
+                                       "Couldn't register notifier rc=%d\n", rc);
+                               return rc;
+                       }
+                       INIT_DELAYED_WORK(&chg->screen_on_work, smblib_screen_on_work);
+               } else
+                       smblib_err(chg, "Unsupported fb notifier \n");
+#endif
                break;
        case PARALLEL_SLAVE:
                break;
@@ -5288,10 +5994,9 @@ int smblib_deinit(struct smb_charger *chg)
                cancel_work_sync(&chg->legacy_detection_work);
                cancel_delayed_work_sync(&chg->uusb_otg_work);
                cancel_delayed_work_sync(&chg->bb_removal_work);
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-               cancel_delayed_work_sync(&chg->fb_state_work);
-               fb_unregister_client(&chg->fb_state_notifier);
-#endif
+               cancel_delayed_work_sync(&chg->typec_reenable_work);
+               cancel_delayed_work_sync(&chg->charger_type_recheck);
+               cancel_delayed_work_sync(&chg->check_vbus_work);
                power_supply_unreg_notifier(&chg->nb);
                smblib_destroy_votables(chg);
                qcom_step_chg_deinit();
@@ -5303,8 +6008,21 @@ int smblib_deinit(struct smb_charger *chg)
                smblib_err(chg, "Unsupported mode %d\n", chg->mode);
                return -EINVAL;
        }
-
+#ifdef CONFIG_FB
+       fb_unregister_client(&chg->smb_fb_notif);
+#endif
        smblib_iio_deinit(chg);
 
        return 0;
 }
+
+static int __init early_parse_off_charge_flag(char *p)
+{
+       if (p) {
+               if (!strcmp(p, "charger"))
+                       off_charge_flag = true;
+       }
+
+       return 0;
+}
+early_param("androidboot.mode", early_parse_off_charge_flag);
index 358cae6..e9c64ae 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
 #include <linux/regulator/driver.h>
 #include <linux/regulator/consumer.h>
 #include <linux/extcon.h>
+#ifdef CONFIG_FB
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#endif
 #include "storm-watch.h"
 
 enum print_reason {
@@ -26,6 +31,15 @@ enum print_reason {
        PR_MISC         = BIT(2),
        PR_PARALLEL     = BIT(3),
        PR_OTG          = BIT(4),
+       PR_OEM          = BIT(5),
+};
+
+enum hvdcp3_type {
+       HVDCP3_NONE = 0,
+       HVDCP3_CLASSA_18W,
+       HVDCP3_CLASSB_27W,
+       USB_PD,
+       HVDCP2_TYPE,
 };
 
 #define DEFAULT_VOTER                  "DEFAULT_VOTER"
@@ -56,6 +70,7 @@ enum print_reason {
 #define PD_SUSPEND_SUPPORTED_VOTER     "PD_SUSPEND_SUPPORTED_VOTER"
 #define PL_DELAY_VOTER                 "PL_DELAY_VOTER"
 #define CTM_VOTER                      "CTM_VOTER"
+#define FB_SCREEN_VOTER                        "FB_SCREEN_VOTER"
 #define SW_QC3_VOTER                   "SW_QC3_VOTER"
 #define AICL_RERUN_VOTER               "AICL_RERUN_VOTER"
 #define LEGACY_UNKNOWN_VOTER           "LEGACY_UNKNOWN_VOTER"
@@ -65,18 +80,27 @@ enum print_reason {
 #define OTG_DELAY_VOTER                        "OTG_DELAY_VOTER"
 #define USBIN_I_VOTER                  "USBIN_I_VOTER"
 #define WEAK_CHARGER_VOTER             "WEAK_CHARGER_VOTER"
+#define CHG_AWAKE_VOTER                 "CHG_AWAKE_VOTER"
 #define WBC_VOTER                      "WBC_VOTER"
 #define OV_VOTER                       "OV_VOTER"
 #define FCC_STEPPER_VOTER              "FCC_STEPPER_VOTER"
-
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-#define FB_SCREEN_VOTER                        "FB_SCREEN_VOTER"
-#endif
+#define CC_FLOAT_VOTER                  "CC_FLOAT_VOTER"
+#define UNSTANDARD_QC2_VOTER           "UNSTANDARD_QC2_VOTER"
+#define HVDCP2_ICL_VOTER               "HVDCP2_ICL_VOTER"
 
 #define VCONN_MAX_ATTEMPTS     3
 #define OTG_MAX_ATTEMPTS       3
 #define BOOST_BACK_STORM_COUNT 3
 #define WEAK_CHG_STORM_COUNT   8
+#define CHG_MONITOR_WORK_DELAY_MS       30000
+#define CC_FLOAT_WORK_START_DELAY_MS    700
+#define BATT_TEMP_CRITICAL_LOW         50
+#define BATT_TEMP_COOL_THR             150
+
+/* QC2.0 voltage UV threshold 7.8V */
+#define QC2_HVDCP_VOL_UV_THR           7800000
+#define CHECK_VBUS_WORK_DELAY_MS       10
+#define UNSTANDARD_HVDCP2_UA           1800000
 
 enum smb_mode {
        PARALLEL_MASTER = 0,
@@ -210,6 +234,7 @@ struct smb_params {
        struct smb_chg_param    dc_icl_div2_mid_hv;
        struct smb_chg_param    dc_icl_div2_hv;
        struct smb_chg_param    jeita_cc_comp;
+       struct smb_chg_param    jeita_fv_comp;
        struct smb_chg_param    freq_buck;
        struct smb_chg_param    freq_boost;
 };
@@ -259,6 +284,9 @@ struct smb_charger {
        struct mutex            ps_change_lock;
        struct mutex            otg_oc_lock;
        struct mutex            vconn_oc_lock;
+#ifdef CONFIG_FB
+       struct mutex            screen_lock;
+#endif
 
        /* power supplies */
        struct power_supply             *batt_psy;
@@ -272,8 +300,11 @@ struct smb_charger {
 
        /* notifiers */
        struct notifier_block   nb;
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       struct notifier_block   fb_state_notifier;
+#ifdef CONFIG_FB
+       struct notifier_block   smb_fb_notif;
+       struct delayed_work     screen_on_work;
+       bool                    screen_on;
+       bool                    checking_in_progress;
 #endif
 
        /* parallel charging */
@@ -312,14 +343,17 @@ struct smb_charger {
        struct work_struct      otg_oc_work;
        struct work_struct      vconn_oc_work;
        struct delayed_work     otg_ss_done_work;
+       struct delayed_work     reg_work;
        struct delayed_work     icl_change_work;
        struct delayed_work     pl_enable_work;
        struct work_struct      legacy_detection_work;
        struct delayed_work     uusb_otg_work;
        struct delayed_work     bb_removal_work;
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       struct delayed_work     fb_state_work;
-#endif
+       struct delayed_work     monitor_low_temp_work;
+       struct delayed_work     cc_float_charge_work;
+       struct delayed_work     typec_reenable_work;
+       struct delayed_work     charger_type_recheck;
+       struct delayed_work     check_vbus_work;
 
        /* cached status */
        int                     voltage_min_uv;
@@ -329,13 +363,17 @@ struct smb_charger {
        int                     boost_threshold_ua;
        int                     system_temp_level;
        int                     thermal_levels;
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
+#ifdef CONFIG_FB
        int                     *thermal_mitigation_dcp;
        int                     *thermal_mitigation_qc3;
        int                     *thermal_mitigation_qc2;
 #else
        int                     *thermal_mitigation;
 #endif
+       int                     jeita_ccomp_cool_delta;
+       int                     jeita_ccomp_hot_delta;
+       int                     jeita_ccomp_low_delta;
+       int                     *thermal_mitigation;
        int                     dcp_icl_ua;
        int                     fake_capacity;
        bool                    step_chg_enabled;
@@ -346,9 +384,11 @@ struct smb_charger {
        bool                    otg_en;
        bool                    vconn_en;
        bool                    suspend_input_on_debug_batt;
+       bool                    legacy;
        int                     otg_attempts;
        int                     vconn_attempts;
        int                     default_icl_ua;
+       int                     last_soc;
        int                     otg_cl_ua;
        bool                    uusb_apsd_rerun_done;
        bool                    pd_hard_reset;
@@ -364,9 +404,6 @@ struct smb_charger {
        bool                    use_extcon;
        bool                    otg_present;
        bool                    fcc_stepper_mode;
-#ifdef CONFIG_MACH_XIAOMI_MSM8998
-       bool                    screen_on;
-#endif
 
        /* workaround flag */
        u32                     wa_flags;
@@ -375,6 +412,10 @@ struct smb_charger {
        bool                    try_sink_active;
        int                     boost_current_ua;
        int                     temp_speed_reading_count;
+       bool            cc_float_detected;
+       bool            float_rerun_apsd;
+       bool            check_vbus_once;
+       bool            unstandard_hvdcp;
 
        /* extcon for VBUS / ID notification to USB for uUSB */
        struct extcon_dev       *extcon;
@@ -387,8 +428,9 @@ struct smb_charger {
        int                     usb_icl_delta_ua;
        int                     pulse_cnt;
 
-       /* last soc */
-       int                     last_soc;
+       /* xiaomi recheck charger type */
+       int                     recheck_charger;
+       int                     precheck_charger_type;
 };
 
 int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -427,6 +469,7 @@ irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data);
 irqreturn_t smblib_handle_chg_state_change(int irq, void *data);
 irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data);
 irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data);
+irqreturn_t smblib_handle_usbin_collapse(int irq, void *data);
 irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data);
 irqreturn_t smblib_handle_usbin_uv(int irq, void *data);
 irqreturn_t smblib_handle_usb_plugin(int irq, void *data);
@@ -456,6 +499,8 @@ int smblib_get_prop_system_temp_level(struct smb_charger *chg,
                                union power_supply_propval *val);
 int smblib_get_prop_input_current_limited(struct smb_charger *chg,
                                union power_supply_propval *val);
+int smblib_get_prop_batt_charge_full(struct smb_charger *chg,
+                               union power_supply_propval *val);
 int smblib_set_prop_input_suspend(struct smb_charger *chg,
                                const union power_supply_propval *val);
 int smblib_set_prop_batt_capacity(struct smb_charger *chg,
@@ -530,6 +575,10 @@ int smblib_set_prop_ship_mode(struct smb_charger *chg,
                                const union power_supply_propval *val);
 int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
                                const union power_supply_propval *val);
+int smblib_set_prop_type_recheck(struct smb_charger *chg,
+                               const union power_supply_propval *val);
+int smblib_get_prop_type_recheck(struct smb_charger *chg,
+                               union power_supply_propval *val);
 void smblib_suspend_on_debug_battery(struct smb_charger *chg);
 int smblib_rerun_apsd_if_required(struct smb_charger *chg);
 int smblib_get_prop_fcc_delta(struct smb_charger *chg,
@@ -549,7 +598,8 @@ int smblib_get_prop_from_bms(struct smb_charger *chg,
 int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
                                const union power_supply_propval *val);
 void smblib_usb_typec_change(struct smb_charger *chg);
-
+int smblib_set_prop_rerun_apsd(struct smb_charger *chg,
+                               const union power_supply_propval *val);
 int smblib_init(struct smb_charger *chg);
 int smblib_deinit(struct smb_charger *chg);
 #endif /* __SMB2_CHARGER_H */
index 4b3f7a0..8784235 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019 XiaoMi, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -594,6 +595,11 @@ enum {
 #define EN_LEGACY_CABLE_DETECTION_BIT          BIT(1)
 #define ALLOW_PD_DRING_UFP_TCCDB_BIT           BIT(0)
 
+#define HVDCP_PULSE_COUNT_MAX_REG      (USBIN_BASE + 0x5B)
+#define PULSE_COUNT_QC2P0_12V          BIT(7)
+#define PULSE_COUNT_QC2P0_9V           BIT(6)
+#define PULSE_COUNT_QC3P0_mask         GENMASK(5, 0)
+
 #define USBIN_ADAPTER_ALLOW_CFG_REG            (USBIN_BASE + 0x60)
 #define USBIN_ADAPTER_ALLOW_MASK               GENMASK(3, 0)
 enum {
@@ -637,6 +643,7 @@ enum {
 #define USBIN_LOAD_CFG_REG                     (USBIN_BASE + 0x65)
 #define USBIN_OV_CH_LOAD_OPTION_BIT            BIT(7)
 #define ICL_OVERRIDE_AFTER_APSD_BIT            BIT(4)
+#define USBIN_COLLAPSE_SEL_MASK                 GENMASK(1, 0)
 
 #define USBIN_ICL_OPTIONS_REG                  (USBIN_BASE + 0x66)
 #define CFG_USB3P0_SEL_BIT                     BIT(2)
index 5944f0f..a682661 100644 (file)
@@ -60,9 +60,9 @@ enum pon_restart_reason {
        PON_RESTART_REASON_DMVERITY_ENFORCE     = 0x05,
        PON_RESTART_REASON_KEYS_CLEAR           = 0x06,
 
-       /* 32 ~ 63 for OEMs/ODMs secific features */
-       PON_RESTART_REASON_OEM_MIN              = 0x20,
-       PON_RESTART_REASON_OEM_MAX              = 0x3f,
+       PON_RESTART_REASON_OEM_BOOT             = 0x07,
+       PON_RESTART_REASON_NORMAL               = 0x20,
+       PON_RESTART_REASON_PANIC                = 0x21,
 };
 
 #ifdef CONFIG_INPUT_QPNP_POWER_ON
index c3764d2..feed4df 100644 (file)
@@ -226,6 +226,7 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_CURRENT_QNOVO,
        POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
        POWER_SUPPLY_PROP_RERUN_AICL,
+       POWER_SUPPLY_PROP_CHARGER_TYPE,
        POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
        POWER_SUPPLY_PROP_SAFETY_TIMER_EXPIRED,
        POWER_SUPPLY_PROP_RESTRICTED_CHARGING,
@@ -253,6 +254,7 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
        POWER_SUPPLY_PROP_HW_CURRENT_MAX,
        POWER_SUPPLY_PROP_REAL_TYPE,
+       POWER_SUPPLY_PROP_HVDCP3_TYPE,
        POWER_SUPPLY_PROP_PR_SWAP,
        POWER_SUPPLY_PROP_CC_STEP,
        POWER_SUPPLY_PROP_CC_STEP_SEL,
@@ -260,6 +262,8 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
        POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
        POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
+       POWER_SUPPLY_PROP_RERUN_APSD,
+       POWER_SUPPLY_PROP_TYPE_RECHECK,
        POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
        POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE,
        POWER_SUPPLY_PROP_BATTERY_INFO,