OSDN Git Service

power: add charging current limitting
authorDemon Singur <demonsingur@gmail.com>
Sat, 24 Mar 2018 17:27:51 +0000 (17:27 +0000)
committerArian <arian.kulmer@web.de>
Tue, 19 Nov 2019 15:24:31 +0000 (16:24 +0100)
Charging at 3200mA while using the phone makes it quite hot.
Decrease the charging current to ~1600mA to prevent bad user
experience and complaints.

After 90 seconds with screen on, vote USB ICL to lower current
to 1600mA.
After 5 seconds with screen off, unvote USB ICL so the current
goes back to 3200mA.

Also, add compatibility with stock hvdcp service that writes to
the system_temp_level property to trigger thermal throttling.

Values taken from MIUI kernel, rewritten to look better and avoid
locking in framebuffer notifiers.

Change-Id: Iedf2789304356221283472ba242211d3ea6256d8

drivers/power/supply/qcom/qpnp-smb2.c
drivers/power/supply/qcom/smb-lib.c
drivers/power/supply/qcom/smb-lib.h

index 8cee5ee..32aef41 100644 (file)
@@ -301,6 +301,64 @@ static int smb2_parse_dt(struct smb2 *chip)
        if (rc < 0)
                chip->dt.wipower_max_uw = -EINVAL;
 
+#ifdef CONFIG_MACH_XIAOMI_MSM8998
+       if (of_find_property(node, "qcom,thermal-mitigation-dcp", &byte_len)) {
+               chg->thermal_mitigation_dcp = devm_kzalloc(chg->dev, byte_len,
+                       GFP_KERNEL);
+
+               if (chg->thermal_mitigation_dcp == NULL)
+                       return -ENOMEM;
+
+               chg->thermal_levels = byte_len / sizeof(u32);
+               rc = of_property_read_u32_array(node,
+                               "qcom,thermal-mitigation-dcp",
+                               chg->thermal_mitigation_dcp,
+                               chg->thermal_levels);
+               if (rc < 0) {
+                       dev_err(chg->dev,
+                               "Couldn't read threm limits rc = %d\n", 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);
+
+               if (chg->thermal_mitigation_qc3 == NULL)
+                       return -ENOMEM;
+
+               chg->thermal_levels = byte_len / sizeof(u32);
+               rc = of_property_read_u32_array(node,
+                               "qcom,thermal-mitigation-qc3",
+                               chg->thermal_mitigation_qc3,
+                               chg->thermal_levels);
+               if (rc < 0) {
+                       dev_err(chg->dev,
+                               "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);
+
+               if (chg->thermal_mitigation_qc2 == NULL)
+                       return -ENOMEM;
+
+               chg->thermal_levels = byte_len / sizeof(u32);
+               rc = of_property_read_u32_array(node,
+                               "qcom,thermal-mitigation-qc2",
+                               chg->thermal_mitigation_qc2,
+                               chg->thermal_levels);
+               if (rc < 0) {
+                       dev_err(chg->dev,
+                               "Couldn't read threm limits rc = %d\n", rc);
+                       return rc;
+               }
+       }
+#else
        if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) {
                chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len,
                        GFP_KERNEL);
@@ -319,6 +377,7 @@ static int smb2_parse_dt(struct smb2 *chip)
                        return rc;
                }
        }
+#endif
 
        of_property_read_u32(node, "qcom,float-option", &chip->dt.float_option);
        if (chip->dt.float_option < 0 || chip->dt.float_option > 4) {
index ae7db6c..f013b43 100644 (file)
 #include "step-chg-jeita.h"
 #include "storm-watch.h"
 
+#ifdef CONFIG_MACH_XIAOMI_MSM8998
+#include <linux/fb.h>
+#endif
+
 #define smblib_err(chg, fmt, ...)              \
        pr_err("%s: %s: " fmt, chg->name,       \
                __func__, ##__VA_ARGS__)        \
@@ -1891,9 +1895,94 @@ int smblib_set_prop_batt_capacity(struct smb_charger *chg,
        return 0;
 }
 
+#ifdef CONFIG_MACH_XIAOMI_MSM8998
+#define SCREEN_ON_ICL          1600000
+#define SCREEN_ON_CHECK_MS     90000
+#define SCREEN_OFF_CHECK_MS    5000
+static void smblib_fb_state_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;
+
+       rc = smblib_get_prop_usb_present(chg, &usb_present);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't check usb present, rc=%d\n", rc);
+               return;
+       }
+
+       if (!usb_present.intval)
+               return;
+
+       if (!chg->usb_icl_votable) {
+               smblib_err(chg, "Couldn't find USB ICL votable\n");
+               return;
+       }
+
+       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);
+       } else {
+               smblib_dbg(chg, PR_MISC, "Screen is off, reset USB ICL\n");
+               vote(chg->usb_icl_votable, FB_SCREEN_VOTER, false, 0);
+       }
+}
+
+static int smblib_fb_state_cb(struct notifier_block *self,
+               unsigned long type, 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;
+       }
+
+       queue_delayed_work(system_power_efficient_wq,
+                       &chg->fb_state_work,
+                       msecs_to_jiffies(check_ms));
+
+end:
+       return NOTIFY_OK;
+}
+#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
+
        if (val->intval < 0)
                return -EINVAL;
 
@@ -1905,19 +1994,57 @@ 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->usb_psy_desc.type) {
+       case POWER_SUPPLY_TYPE_USB_HVDCP:
+               thermal_mitigation = chg->thermal_mitigation_qc2;
+               break;
+       case POWER_SUPPLY_TYPE_USB_HVDCP_3:
+               thermal_mitigation = chg->thermal_mitigation_qc3;
+               break;
+       case POWER_SUPPLY_TYPE_USB_DCP:
+       default:
+               thermal_mitigation = chg->thermal_mitigation_dcp;
+               throttle_current = false;
+               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;
 }
 
@@ -5073,6 +5200,10 @@ int smblib_init(struct smb_charger *chg)
        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
+
        chg->fake_capacity = -EINVAL;
        chg->fake_input_current_limited = -EINVAL;
 
@@ -5107,6 +5238,16 @@ 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");
                break;
@@ -5136,6 +5277,10 @@ 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
                power_supply_unreg_notifier(&chg->nb);
                smblib_destroy_votables(chg);
                qcom_step_chg_deinit();
index 5ca5e92..5e1a7aa 100644 (file)
@@ -69,6 +69,10 @@ enum print_reason {
 #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 VCONN_MAX_ATTEMPTS     3
 #define OTG_MAX_ATTEMPTS       3
 #define BOOST_BACK_STORM_COUNT 3
@@ -268,6 +272,9 @@ struct smb_charger {
 
        /* notifiers */
        struct notifier_block   nb;
+#ifdef CONFIG_MACH_XIAOMI_MSM8998
+       struct notifier_block   fb_state_notifier;
+#endif
 
        /* parallel charging */
        struct parallel_params  pl;
@@ -310,6 +317,9 @@ struct smb_charger {
        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
 
        /* cached status */
        int                     voltage_min_uv;
@@ -319,7 +329,13 @@ struct smb_charger {
        int                     boost_threshold_ua;
        int                     system_temp_level;
        int                     thermal_levels;
+#ifdef CONFIG_MACH_XIAOMI_MSM8998
+       int                     *thermal_mitigation_dcp;
+       int                     *thermal_mitigation_qc3;
+       int                     *thermal_mitigation_qc2;
+#else
        int                     *thermal_mitigation;
+#endif
        int                     dcp_icl_ua;
        int                     fake_capacity;
        bool                    step_chg_enabled;
@@ -348,6 +364,9 @@ 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;