diff --git a/drivers/power/mmi_parallel_charger_iio/Kbuild b/drivers/power/mmi_parallel_charger_iio/Kbuild index af272f4cf7a5..2210142a1c10 100644 --- a/drivers/power/mmi_parallel_charger_iio/Kbuild +++ b/drivers/power/mmi_parallel_charger_iio/Kbuild @@ -9,6 +9,8 @@ mmi_parallel_charger_iio-objs += mmi_charger_core.o mmi_parallel_charger_iio-objs += mmi_charger_pump_policy.o mmi_parallel_charger_iio-objs += sc8549_charger.o mmi_parallel_charger_iio-objs += qpnp_pmic_charger.o +mmi_parallel_charger_iio-objs += mmi_qc3p.o +mmi_parallel_charger_iio-objs += mmi_qc3p_cp_policy.o #ifeq ($(CONFIG_MMI_PL_CP_POLICY), y) #endif diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.c b/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.c index cbed740f3eb4..fc44c0df0935 100644 --- a/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.c +++ b/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.c @@ -69,6 +69,14 @@ int mmi_set_charing_current(struct mmi_charger_device *chrg, u32 uA) return -ENOTSUPP; } +int mmi_get_vbus(struct mmi_charger_device *chrg, u32 *mv) +{ + if(chrg != NULL && chrg->ops != NULL && chrg->ops->get_vbus) + return chrg->ops->get_vbus(chrg,mv); + + return -ENOTSUPP; +} + int mmi_get_input_current_settled(struct mmi_charger_device *chrg, u32 *uA) { if(chrg != NULL && chrg->ops != NULL && chrg->ops->get_input_current_settled) diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.h b/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.h index caec2d80e67b..b4020176beb2 100644 --- a/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.h +++ b/drivers/power/mmi_parallel_charger_iio/mmi_charger_class.h @@ -97,6 +97,7 @@ struct mmi_charger_ops { int (*get_charging_current)(struct mmi_charger_device *chrg, u32 *uA); int (*set_charging_current)(struct mmi_charger_device *chrg, u32 uA); int (*get_input_current_settled)(struct mmi_charger_device *chrg, u32 *uA); + int (*get_vbus)(struct mmi_charger_device *chrg, u32 *mv); int (*get_input_current)(struct mmi_charger_device *chrg, u32 *uA); int (*set_input_current)(struct mmi_charger_device *chrg, u32 uA); int (*update_charger_status)(struct mmi_charger_device *chrg); @@ -122,6 +123,7 @@ extern int mmi_set_input_current(struct mmi_charger_device *chrg, u32 uA); extern int mmi_update_charger_status(struct mmi_charger_device *chrg); extern int mmi_update_charger_error(struct mmi_charger_device *chrg); extern int mmi_clear_charger_error(struct mmi_charger_device *chrg); +extern int mmi_get_vbus(struct mmi_charger_device *chrg, u32 *mv); extern struct mmi_charger_ops sc8549_charger_ops; extern struct mmi_charger_ops qpnp_pmic_charger_ops; extern struct mmi_charger_device *mmi_charger_device_register(const char *name, diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.c b/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.c index 593de631a79e..0888e0345cae 100644 --- a/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.c +++ b/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.c @@ -45,6 +45,7 @@ #include "mmi_charger_core.h" #include "mmi_charger_core_iio.h" #include "mmi_charger_policy.h" +#include "mmi_qc3p.h" #include #include @@ -132,6 +133,7 @@ static int mmi_charger_init_iio_psy(struct mmi_charger_manager *chip, return rc; } +static int qc3p_volt_max_init = 0; static int pd_volt_max_init = 0; static int pd_curr_max_init = 0; static int *dt_temp_zones; @@ -1107,8 +1109,33 @@ void clear_chrg_dev_error_cnt(struct mmi_charger_manager *chip, struct mmi_cp_po return; } +static void kick_qc3p_sm(struct mmi_charger_manager *chip, int ms) +{ + if (!chip->qc3p_sm_work_running) { + mmi_chrg_dbg(chip, PR_INTERRUPT, + "launch mmi qc3p chrg sm work\n"); + mmi_qc3p_chrg_policy_clear(chip); //todo + schedule_delayed_work(&chip->mmi_qc3p_chrg_sm_work, // + msecs_to_jiffies(ms)); //todo + chip->qc3p_sm_work_running = true; + } else + mmi_chrg_dbg(chip, PR_INTERRUPT, + "mmi chrg qc3p sm work already existed\n"); +} + +static void cancel_qc3p_sm(struct mmi_charger_manager *chip) +{ + cancel_delayed_work_sync(&chip->mmi_qc3p_chrg_sm_work); + flush_delayed_work(&chip->mmi_qc3p_chrg_sm_work); + mmi_qc3p_chrg_policy_clear(chip); + chip->qc3p_sm_work_running = false; + chip->qc3p_volt_max = qc3p_volt_max_init; + mmi_chrg_dbg(chip, PR_INTERRUPT, + "cancel sync and flush mmi chrg qc3p sm work\n"); +} + static void mmi_awake_vote(struct mmi_charger_manager *chip, bool awake) { if (awake == chip->awake) @@ -1327,12 +1354,18 @@ static void mmi_heartbeat_work(struct work_struct *work) break; } } + } + if (!chip->qc3p_sm_work_running && chip->vbus_present) + chip->qc3p_active = mmi_qc3p_power_active(chip); - if (chip->pd_pps_support - && !chip->factory_mode) { - mmi_chrg_info(chip, "MMI: Heartbeat!, launch sm work\n"); - kick_sm(chip, 100); - } + if (chip->pd_pps_support + && !chip->factory_mode) { + mmi_chrg_info(chip, "MMI: Heartbeat!, launch sm work\n"); + kick_sm(chip, 100); + } else if(chip->qc3p_active + && !chip->factory_mode) { + mmi_chrg_info(chip, "MMI: Heartbeat!, launch qc3p sm work\n"); + kick_qc3p_sm(chip, 100); } if (chip->use_batt_age) @@ -1455,19 +1488,29 @@ static void psy_changed_work_func(struct work_struct *work) chip->pd_pps_support, chip->pd_volt_max, chip->pd_curr_max); + if (chip->vbus_present) + chip->qc3p_active = mmi_qc3p_power_active(chip); if (chip->vbus_present && chip->pd_pps_support && !chip->factory_mode) { kick_sm(chip, 100); + } else if (chip->vbus_present + && chip->qc3p_active + && !chip->factory_mode) { + kick_qc3p_sm(chip, 100); } else { cancel_sm(chip); - + cancel_qc3p_sm(chip); chip->pd_pps_support = false; + chip->qc3p_active = false; } + return; } - +#define DEFAULT_IBUS_MAX_MA 3000 +#define DEFAULT_QC3P_VOLT_STEPS 20000 +#define DEFAULT_QC3P_VOLT_MAX 11000000 #define DEFAULT_BATT_OVP_LMT 4475000 #define DEFAULT_PL_CHRG_VBATT_MIN 3600000 #define DEFAULT_PPS_VOLT_STEPS 20000 @@ -1567,6 +1610,27 @@ static int mmi_chrg_manager_parse_dt(struct mmi_charger_manager *chip) DEFAULT_PPS_CURR_MAX; pd_curr_max_init = chip->pd_curr_max; + rc = of_property_read_u32(node, + "mmi,qc3p-max-ibus-ma", + &chip->qc3p_max_ibus_ma); + if (rc < 0) + chip->qc3p_max_ibus_ma = + DEFAULT_IBUS_MAX_MA; + rc = of_property_read_u32(node, + "mmi,qc3p-volt-steps", + &chip->qc3p_volt_steps); + if (rc < 0) + chip->qc3p_volt_steps = + DEFAULT_QC3P_VOLT_STEPS; + + rc = of_property_read_u32(node, + "mmi,qc3p-volt-max", + &chip->qc3p_volt_max); + if (rc < 0) + chip->qc3p_volt_max = + DEFAULT_QC3P_VOLT_MAX; + qc3p_volt_max_init = chip->qc3p_volt_max; + for_each_child_of_node(node, child) chip->mmi_chrg_dev_num++; @@ -1864,6 +1928,8 @@ int mmi_chrg_policy_init(struct mmi_charger_manager *chip, chrg_dev_init(chip, &g_chrg_list); chip->pps_volt_comp = PPS_INIT_VOLT_COMP; INIT_DELAYED_WORK(&chip->mmi_chrg_sm_work, mmi_chrg_sm_work_func); + chip->qc3p_volt_comp = QC3P_INIT_VOLT_COMP; + INIT_DELAYED_WORK(&chip->mmi_qc3p_chrg_sm_work, mmi_qc3p_chrg_sm_work_func); return 0; } diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.h b/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.h index bc92dece7752..a0dba6944d0b 100644 --- a/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.h +++ b/drivers/power/mmi_parallel_charger_iio/mmi_charger_core.h @@ -280,9 +280,32 @@ struct mmi_charger_manager { int mmi_chrg_dev_num; struct mmi_charger_device **chrg_list; /*charger device list*/ + + /*qc3p*/ + int qc3p_max_ibus_ma; + int qc3p_power; + bool qc3p_active; + bool qc3p_sm_work_running; + struct delayed_work mmi_qc3p_chrg_sm_work; + int qc3p_request_volt; + int qc3p_request_volt_prev; + int qc3p_target_volt; + int qc3p_batt_therm_volt; + int qc3p_sys_therm_volt; + bool qc3p_recovery_pmic_chrg; + bool qc3p_sys_therm_cooling; + bool qc3p_sys_therm_force_pmic_chrg; + bool qc3p_batt_therm_cooling; + int qc3p_batt_therm_cooling_cnt; + int qc3p_volt_comp; + int qc3p_ibus_max_volt; + int qc3p_volt_steps; + int qc3p_volt_max; }; #define PPS_INIT_VOLT_COMP 500000 +#define QC3P_INIT_VOLT_COMP 500000 +extern void mmi_qc3p_chrg_sm_work_func(struct work_struct *work); extern struct mmi_cp_policy_dev g_chrg_list; extern const struct mmi_chrg_dev_ops dev_ops[]; extern void clear_chrg_dev_error_cnt(struct mmi_charger_manager *chip, struct mmi_cp_policy_dev *chrg_list); diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_charger_core_iio.h b/drivers/power/mmi_parallel_charger_iio/mmi_charger_core_iio.h index 0e2ea27f9874..e61b2565c911 100644 --- a/drivers/power/mmi_parallel_charger_iio/mmi_charger_core_iio.h +++ b/drivers/power/mmi_parallel_charger_iio/mmi_charger_core_iio.h @@ -16,6 +16,10 @@ enum mmi_charger_ext_iio_channels { SMB5_TYPEC_MODE, SMB5_USB_INPUT_CURRENT_SETTLED, SMB5_USB_PD_ACTIVE, + /*qc3p*/ + SMB5_USB_REAL_TYPE, + SMB5_DP_DM, + SMB5_QC3P_POWER, /*sc8549*/ SC8549_CP_ENABLE, SC8549_INPUT_CURRENT_NOW, @@ -31,6 +35,10 @@ static const char * const mmi_charger_ext_iio_chan_name[] = { [SMB5_TYPEC_MODE] = "usb_typec_mode", [SMB5_USB_INPUT_CURRENT_SETTLED] = "usb_input_current_settled", [SMB5_USB_PD_ACTIVE] = "usb_pd_active", + /*qc3p*/ + [SMB5_USB_REAL_TYPE] = "usb_real_type", + [SMB5_DP_DM] = "battery_dp_dm", + [SMB5_QC3P_POWER] = "usb_qc3p_power", /*sc8549*/ [SC8549_CP_ENABLE] = "sc8549_cp_enable", [SC8549_INPUT_CURRENT_NOW] = "sc8549_input_current_now", diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_charger_policy.h b/drivers/power/mmi_parallel_charger_iio/mmi_charger_policy.h index 5f58555c8be0..f7b6554a5cd9 100644 --- a/drivers/power/mmi_parallel_charger_iio/mmi_charger_policy.h +++ b/drivers/power/mmi_parallel_charger_iio/mmi_charger_policy.h @@ -29,4 +29,5 @@ #define __MMI_CHRG_POLICY_H_ extern void mmi_chrg_policy_clear(struct mmi_charger_manager *chip); extern void mmi_chrg_enable_all_cp(struct mmi_charger_manager *chip, int val); +extern void mmi_qc3p_chrg_policy_clear(struct mmi_charger_manager *chip); #endif diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_qc3p.c b/drivers/power/mmi_parallel_charger_iio/mmi_qc3p.c new file mode 100644 index 000000000000..bc465469c5f1 --- /dev/null +++ b/drivers/power/mmi_parallel_charger_iio/mmi_qc3p.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2012 Motorola Mobility, LLC. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "mmi_charger_core.h" +#include "mmi_charger_core_iio.h" +#include + +bool mmi_qc3p_power_active(struct mmi_charger_manager *chg) +{ + int ret, iio_val; + + ret = mmi_charger_read_iio_chan(chg, SMB5_USB_REAL_TYPE, &iio_val); + if (ret < 0) { + mmi_chrg_err(chg, "Couldn't read charger type rc=%d\n", ret); + return false; + } + if (iio_val != QTI_POWER_SUPPLY_TYPE_USB_HVDCP_3P5) + return false; + + ret = mmi_charger_read_iio_chan(chg, SMB5_QC3P_POWER, &iio_val); + if (ret < 0) { + mmi_chrg_err(chg, "Couldn't read qc3p power rc=%d\n", ret); + return false; + } + chg->qc3p_power = iio_val; + mmi_chrg_info(chg, "qc3p_power =%d\n", chg->qc3p_power); + + if (chg->qc3p_power == QTI_POWER_SUPPLY_QC3P_27W || + chg->qc3p_power == QTI_POWER_SUPPLY_QC3P_45W) + return true; + else + return false; +} + +#define QC3P_PULSE_COUNT_MAX ((11000 - 5000) / 20 + 10) +int mmi_qc3p_set_vbus_voltage(struct mmi_charger_manager *chg, int target_mv) +{ + int rc = -EINVAL; + union power_supply_propval val = {0, }; + int pulse_cnt, curr_vbus_mv, step, i; + + rc = mmi_charger_read_iio_chan(chg, SMB5_DP_DM, &val.intval); + if (rc < 0) { + mmi_chrg_err(chg, "Couldn't read dpdm pulse count rc=%d\n", rc); + return -EINVAL; + } else { + mmi_chrg_info(chg, "DP DM pulse count = %d\n", val.intval); + pulse_cnt = val.intval; + } + + rc = mmi_get_vbus(chg->chrg_list[CP_MASTER], + &curr_vbus_mv); + if (rc) { + mmi_chrg_err(chg, "Unable to read USB voltage: %d\n", rc); + return -EINVAL; + } + + if(target_mv < curr_vbus_mv) { + step = (curr_vbus_mv - target_mv) / 20; + val.intval = QTI_POWER_SUPPLY_DP_DM_DM_PULSE; + if (pulse_cnt <= step) + step = pulse_cnt; + } else { + step = (target_mv - curr_vbus_mv) / 20; + val.intval = QTI_POWER_SUPPLY_DP_DM_DP_PULSE; + if (step + pulse_cnt > QC3P_PULSE_COUNT_MAX) + step = QC3P_PULSE_COUNT_MAX - pulse_cnt; + } + + mmi_chrg_info(chg, "curr_vbus= %d, target_vbus = %d, step = %d\n",curr_vbus_mv, target_mv, step); + for (i = 0; i < step; i++) { + rc = mmi_charger_write_iio_chan(chg, SMB5_DP_DM, val.intval); + if (rc < 0) { + mmi_chrg_err(chg, "Couldn't set dpdm pulse rc=%d\n", rc); + break; + } + + if (i < step - 1) + udelay(5000); + } + + rc = mmi_get_vbus(chg->chrg_list[CP_MASTER], + &curr_vbus_mv); + if (rc) { + mmi_chrg_err(chg, "Unable to read VBUS: %d\n", rc); + return -EINVAL; + } + mmi_chrg_info(chg, "result_vbus= %d\n",curr_vbus_mv); + return curr_vbus_mv; +} diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_qc3p.h b/drivers/power/mmi_parallel_charger_iio/mmi_qc3p.h new file mode 100644 index 000000000000..7b3af65832c8 --- /dev/null +++ b/drivers/power/mmi_parallel_charger_iio/mmi_qc3p.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 Motorola Mobility, LLC. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +extern bool mmi_qc3p_power_active(struct mmi_charger_manager *chg); +extern int mmi_qc3p_set_vbus_voltage(struct mmi_charger_manager *chg, int target_mv); + diff --git a/drivers/power/mmi_parallel_charger_iio/mmi_qc3p_cp_policy.c b/drivers/power/mmi_parallel_charger_iio/mmi_qc3p_cp_policy.c new file mode 100644 index 000000000000..6eab58725572 --- /dev/null +++ b/drivers/power/mmi_parallel_charger_iio/mmi_qc3p_cp_policy.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 2021 Motorola Mobility, LLC. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mmi_charger_core.h" +#include "mmi_qc3p.h" + +#define SWITCH_CHARGER_QC3P_VOLT 5000000 +typedef enum { + PM_QC3P_STATE_DISCONNECT, + PM_QC3P_STATE_ENTRY, + PM_QC3P_STATE_SW_ENTRY, + PM_QC3P_STATE_SW_LOOP, + PM_QC3P_STATE_CHRG_PUMP_ENTRY, + PM_QC3P_STATE_SINGLE_CP_ENTRY, + PM_QC3P_STATE_DULE_CP_ENTRY, + PM_QC3P_STATE_TUNNING_VOLT, + PM_QC3P_STATE_CP_CC_LOOP, + PM_QC3P_STATE_CP_CV_LOOP, + PM_QC3P_STATE_CP_QUIT, + PM_QC3P_STATE_RECOVERY_SW, + PM_QC3P_STATE_STOP_CHARGE, +} pm_sm_qc3p_state_t; + +const unsigned char *pm_qc3p_state_str[] = { + "PM_QC3P_STATE_DISCONNECT", + "PM_QC3P_STATE_ENTRY", + "PM_QC3P_STATE_SW_ENTRY", + "PM_QC3P_STATE_SW_LOOP", + "PM_QC3P_STATE_CHRG_PUMP_ENTRY", + "PM_QC3P_STATE_SINGLE_CP_ENTRY", + "PM_QC3P_STATE_DULE_CP_ENTRY", + "PM_QC3P_STATE_TUNNING_VOLT", + "PM_QC3P_STATE_CP_CC_LOOP", + "PM_QC3P_STATE_CP_CV_LOOP", + "PM_QC3P_STATE_CP_QUIT", + "PM_QC3P_STATE_RECOVERY_SW", + "PM_QC3P_STATE_STOP_CHARGE", +}; + +static pm_sm_qc3p_state_t qc3p_sm_state = PM_QC3P_STATE_DISCONNECT; +static int qc3p_chrg_cc_power_tunning_cnt = 0; +static int qc3p_chrg_cv_taper_tunning_cnt = 0; +static int qc3p_chrg_cv_delta_volt = 0; +static int qc3p_quit_slave_chrg_cnt = 0; +static int qc3p_batt_curr_roof = 0; +static int qc3p_constant_power_cnt = 0; + +static void mmi_chrg_qc3p_sm_move_state(struct mmi_charger_manager *chip, pm_sm_qc3p_state_t state) +{ + mmi_chrg_dbg(chip, PR_INTERRUPT, "pm_state change:%s -> %s\n", + pm_qc3p_state_str[qc3p_sm_state], pm_qc3p_state_str[state]); + qc3p_sm_state = state; + qc3p_constant_power_cnt = 0; + qc3p_batt_curr_roof = 0; +} + +#define QC3P_VOLT_COMP_DELTA 300000 +static void qc3p_chrg_policy_error_recovery(struct mmi_charger_manager *chip, + struct mmi_cp_policy_dev *chrg_list) +{ + int chrg_num = 0, i = 0, chrg_error_type= 0; + struct mmi_charger_device *chrg_dev; + chrg_num = chip->mmi_chrg_dev_num; + + for (i = 0; i < chrg_num; i++) { + + switch (i) { + case PMIC_SW: + break; + case CP_MASTER: + if (is_charger_exist(dev_ops[CP_MASTER].dev_name)) { + chrg_dev = chrg_list->chrg_dev[CP_MASTER]; + chrg_error_type = chrg_dev->charger_error.chrg_err_type; + if (chrg_error_type & (1 << MMI_BUS_UCP_ALARM_BIT) || + chrg_error_type & (1 << MMI_BUS_UCP_FAULT_BIT)) { + mmi_chrg_info(chip,"CP master bus ucp error %d, cnt %d," + "qc3p volt comp %dmV\n", + chrg_error_type, + chrg_dev->charger_error.bus_ucp_err_cnt, + chip->qc3p_volt_comp); + + if (chrg_dev->charger_error.bus_ucp_err_cnt > 3) { + if (chrg_list->cp_slave) { + chrg_list->cp_slave = false; + chrg_dev->charger_error.bus_ucp_err_cnt = 0; + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_CHRG_PUMP_ENTRY); + } else { + chip->qc3p_recovery_pmic_chrg = true; + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_SW_ENTRY); + chrg_dev->charger_error.bus_ucp_err_cnt = 0; + } + } else if (chrg_dev->charger_error.bus_ucp_err_cnt > 6) { + chip->qc3p_recovery_pmic_chrg = true; + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_SW_ENTRY); + chrg_dev->charger_error.bus_ucp_err_cnt = 0; + } + + chrg_dev->charger_error.bus_ucp_err_cnt++; + chip->qc3p_volt_comp += QC3P_VOLT_COMP_DELTA; + mmi_chrg_info(chip,"Restart charging, " + "increase qc3p volt comp %dmV\n", + chip->qc3p_volt_comp); + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_CHRG_PUMP_ENTRY); + mmi_clear_charger_error(chrg_dev); + }else if (chrg_error_type & (1 << MMI_BUS_OCP_ALARM_BIT) || + chrg_error_type & (1 << MMI_BUS_OCP_FAULT_BIT) || + chrg_error_type & (1 << MMI_CONV_OCP_FAULT_BIT)) { + mmi_chrg_info(chip,"CP master ocp error %d, cnt %d," + "qc3p volt comp %dmV\n", + chrg_error_type, + chrg_dev->charger_error.bus_ocp_err_cnt, + chip->qc3p_volt_comp); + if (chrg_dev->charger_error.bus_ocp_err_cnt > 3) { + chip->qc3p_recovery_pmic_chrg = true; + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_SW_ENTRY); + chrg_dev->charger_error.bus_ocp_err_cnt = 0; + } + chrg_dev->charger_error.bus_ocp_err_cnt++; + chip->qc3p_volt_comp -= QC3P_VOLT_COMP_DELTA; + if (chip->qc3p_volt_comp < 0) + chip->qc3p_volt_comp = 0; + mmi_chrg_info(chip,"Restart charging, " + "decrease qc3p volt comp %dmV\n", + chip->qc3p_volt_comp); + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_CHRG_PUMP_ENTRY); + mmi_clear_charger_error(chrg_dev); + } + } + break; + case CP_SLAVE: + break; + default: + mmi_chrg_err(chip,"No mmi_chrg_dev found %d !\n",i); + break; + } + } + return; +} + +void mmi_qc3p_chrg_enable_all_cp(struct mmi_charger_manager *chip, int val) +{ + struct mmi_cp_policy_dev *chrg_list = &g_chrg_list; + bool enable = !!val; + + mmi_chrg_dbg(chip, PR_MOTO,"enable all cp = %d\n", enable); + if (enable) { + if (chip->cp_disable == false) + return; + + cancel_delayed_work_sync(&chip->mmi_qc3p_chrg_sm_work); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CHRG_PUMP_ENTRY); + chip->cp_disable = false; + schedule_delayed_work(&chip->mmi_qc3p_chrg_sm_work, + msecs_to_jiffies(0)); + + } else { + if(chrg_list->cp_master + && !chrg_list->chrg_dev[CP_MASTER]->charger_enabled) + return; + + cancel_delayed_work_sync(&chip->mmi_qc3p_chrg_sm_work); + + chip->cp_disable = true; + if (chrg_list->cp_slave + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + } + + if (chrg_list->cp_master + && chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], false); + } + + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_RECOVERY_SW); + schedule_delayed_work(&chip->mmi_qc3p_chrg_sm_work, + msecs_to_jiffies(0)); + } +} + +#define QC3P_HEARTBEAT_SHORT_DELAY_MS 1000 +#define QC3P_HEARTBEAT_lOOP_WAIT_MS 3000 +#define QC3P_HEARTBEAT_TUNNING_MS 100 +#define QC3P_HEARTBEAT_NEXT_STATE_MS 100 +#define QC3P_HEARTBEAT_CANCEL -1 +#define QC3P_CC_CURR_DEBOUNCE 100000 +#define QC3P_CV_TAPPER_COUNT 3 +#define QC3P_CC_POWER_COUNT 3 +#define QC3P_CV_DELTA_VOLT 100000 +#define QC3P_COOLING_DELTA_POWER 100000 +#define QC3P_COOLING_MAX_CNT 5 +#define QC3P_DISABLE_CHRG_LIMIT -1 +#define QC3P_CP_CHRG_SOC_LIMIT 90 +#define QC3P_CONT_PWR_CNT 5 + +void qc3p_clear_chg_manager(struct mmi_charger_manager *chip) +{ + mmi_chrg_dbg(chip, PR_INTERRUPT, "clear mmi qc3p chrg manager!\n"); + chip->qc3p_request_volt = 0; + chip->qc3p_request_volt_prev = 0; + chip->qc3p_target_volt = 0; + chip->qc3p_batt_therm_volt = 0; + chip->qc3p_sys_therm_volt = 0; + chip->qc3p_recovery_pmic_chrg = false; + chip->qc3p_sys_therm_cooling= false; + chip->qc3p_sys_therm_force_pmic_chrg = false; + chip->qc3p_batt_therm_cooling = false; + chip->qc3p_batt_therm_cooling_cnt = 0; + +} + +void mmi_qc3p_chrg_policy_clear(struct mmi_charger_manager *chip) { + struct mmi_cp_policy_dev *chrg_list = &g_chrg_list; + chrg_dev_init(chip, &g_chrg_list); + clear_chrg_dev_error_cnt(chip, &g_chrg_list); + qc3p_clear_chg_manager(chip); + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + QC3P_DISABLE_CHRG_LIMIT); + qc3p_sm_state = PM_QC3P_STATE_DISCONNECT; + chip->qc3p_volt_comp = QC3P_INIT_VOLT_COMP; + qc3p_quit_slave_chrg_cnt = 0; + qc3p_chrg_cc_power_tunning_cnt = 0; + qc3p_chrg_cv_taper_tunning_cnt = 0; + qc3p_chrg_cv_delta_volt = 0; + qc3p_constant_power_cnt = 0; + qc3p_batt_curr_roof = 0; + return; +} + +void mmi_qc3p_chrg_sm_work_func(struct work_struct *work) +{ + struct mmi_charger_manager *chip = container_of(work, + struct mmi_charger_manager, mmi_qc3p_chrg_sm_work.work); + int i = 0, rc = 0; + int ibatt_curr = 0, vbatt_volt = 0, batt_temp = 0, vbus_pres = 0; + int batt_soc = 0; + int heartbeat_dely_ms = 0; + int pmic_sys_therm_level = 0; + bool zone_change = false; + int ibus_total_ma = 0; + int cooling_volt = 0; + bool ignore_hysteresis_degc = false; + struct mmi_chrg_step_info *chrg_step; + union power_supply_propval prop = {0,}; + struct mmi_cp_policy_dev *chrg_list = &g_chrg_list; + + mmi_chrg_dbg(chip, PR_MOTO, "\n\n\n"); + + mmi_chrg_dbg(chip, PR_MOTO, "schedule SM work, sm state %s \n", + pm_qc3p_state_str[qc3p_sm_state]); + + mmi_chrg_dbg(chip, PR_MOTO, "pmic-sw is exist: %d " + "cp-master is exist: %d " + "cp-slave is exist: %d\n", + chrg_list->pmic_sw, + chrg_list->cp_master, + chrg_list->cp_slave); + if (!chrg_list->pmic_sw) { + mmi_chrg_err(chip,"PMIC-SW isn't exist, force quite mmi chrg sm work !\n"); + return; + } + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &prop); + if (!rc) + pmic_sys_therm_level = prop.intval; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + if (!rc) + ibatt_curr = prop.intval; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_TEMP, &prop); + if (!rc) + batt_temp = prop.intval / 10; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &prop); + if (!rc) + batt_soc = prop.intval; + + + if (ibatt_curr < 0) + ibatt_curr *= -1; + + + mmi_update_all_charger_status(chip); + mmi_update_all_charger_error(chip); + + if (chip->extrn_sense) { + ibatt_curr = chrg_list->chrg_dev[CP_MASTER]->charger_data.ibatt_curr; + ibatt_curr *= 1000; + if (ibatt_curr < 0) + ibatt_curr *= -1; + } + vbatt_volt = chrg_list->chrg_dev[CP_MASTER]->charger_data.vbatt_volt; + vbatt_volt *= 1000; + + vbus_pres = chrg_list->chrg_dev[PMIC_SW]->charger_data.vbus_pres; + if (!vbus_pres) { + for (i = 0; i < 3; i++) { + mmi_update_all_charger_status(chip); + vbus_pres = chrg_list->chrg_dev[PMIC_SW]->charger_data.vbus_pres; + mmi_chrg_info(chip, "Retry check charger status, vbus %d\n", vbus_pres); + if (vbus_pres) { + mmi_chrg_info(chip, "Get vbus present , continue to charging\n"); + break; + } + msleep(100); + } + } + + mmi_chrg_info(chip, "battery current %d\n", ibatt_curr); + mmi_chrg_info(chip, "battery voltage %d\n", vbatt_volt); + mmi_chrg_info(chip, "battery temp %d\n", batt_temp); + mmi_chrg_info(chip, "battery capacity %d\n", batt_soc); + + if (vbus_pres && + (qc3p_sm_state == PM_QC3P_STATE_TUNNING_VOLT + || qc3p_sm_state == PM_QC3P_STATE_CP_CC_LOOP + || qc3p_sm_state == PM_QC3P_STATE_CP_CV_LOOP)) { + mmi_dump_charger_error(chip, chrg_list->chrg_dev[CP_MASTER]); + qc3p_chrg_policy_error_recovery(chip, chrg_list); + } + + if (qc3p_sm_state == PM_QC3P_STATE_CP_CV_LOOP) + ignore_hysteresis_degc = true; + zone_change = mmi_find_temp_zone(chip, batt_temp, ignore_hysteresis_degc); + chrg_step = &chip->chrg_step; + + if (chip->pres_temp_zone == ZONE_COLD + || chip->pres_temp_zone == ZONE_HOT + || !chrg_list->chrg_dev[PMIC_SW]->charger_enabled + || vbatt_volt > chip->batt_ovp_lmt) { + + mmi_chrg_info(chip, "Force stop charging, " + "pres_temp_zone %d, " + "pmic charger enabled %d, " + "vbatt_volt %dmv, " + "batt ovp limit %dmv\n", + chip->pres_temp_zone, + chrg_list->chrg_dev[PMIC_SW]->charger_enabled, + vbatt_volt, chip->batt_ovp_lmt); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_STOP_CHARGE); + } + + if (!vbus_pres) { + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_DISCONNECT); + } else if (qc3p_sm_state == PM_QC3P_STATE_ENTRY + || qc3p_sm_state == PM_QC3P_STATE_STOP_CHARGE) { + mmi_find_chrg_step(chip, chip->pres_temp_zone, vbatt_volt); + } else if (qc3p_sm_state == PM_QC3P_STATE_DISCONNECT) { + mmi_get_input_current_settled(chrg_list->chrg_dev[PMIC_SW], + &chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_find_chrg_step(chip, chip->pres_temp_zone, vbatt_volt); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_ENTRY); + } else if (zone_change && + chip->pres_temp_zone != ZONE_COLD && + chip->pres_temp_zone != ZONE_HOT) { + + if (batt_temp >= chrg_step->temp_c) { + mmi_chrg_info(chip, "battery temp %d, temp thre %d " + "Enter into COOLING LOOP !\n", + batt_temp, chrg_step->temp_c); + chip->qc3p_batt_therm_cooling = true; + chip->qc3p_batt_therm_volt = chip->qc3p_request_volt_prev; + } else if (!chip->qc3p_batt_therm_cooling && + !ignore_hysteresis_degc) { + mmi_chrg_info(chip, "battery temp %d, temp thre %d " + "Restart select chrg step and temp zone !\n", + batt_temp, chrg_step->temp_c); + mmi_find_chrg_step(chip, chip->pres_temp_zone, vbatt_volt); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_ENTRY); + } + } + + mmi_chrg_dbg(chip, PR_MOTO, "temp zone %d, is_changed %d, " + "chrg_step %d, " + "step cc curr %d, step cv volt %d, " + "step cv tapper curr %d\n", + chip->pres_temp_zone, zone_change, + chrg_step->pres_chrg_step, + chrg_step->chrg_step_cc_curr, + chrg_step->chrg_step_cv_volt, + chrg_step->chrg_step_cv_tapper_curr); + switch (qc3p_sm_state) { + case PM_QC3P_STATE_DISCONNECT: + mmi_chrg_info(chip,"vbus disconnect !, jump to PM_QC3P_STATE_DISCONNECT," + "recovery PMIC-SW limitation, and close CP charg\n"); + if (chrg_list->cp_slave + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + } + + if (chrg_list->cp_master + && chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], false); + } + + if (chrg_list->chrg_dev[PMIC_SW]->charger_limited) { + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_chrg_info(chip,"recovery PMIC-SW ichg lmt ,%d uA\n", + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + QC3P_DISABLE_CHRG_LIMIT); + chrg_list->chrg_dev[PMIC_SW]->charger_limited = false; + } + + heartbeat_dely_ms = QC3P_HEARTBEAT_CANCEL; + break; + case PM_QC3P_STATE_ENTRY: + if (chrg_list->cp_slave + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + } + + if (chrg_list->cp_master + && chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], false); + } + + if (chip->qc3p_active + && chrg_list->cp_master + && vbatt_volt > chip->pl_chrg_vbatt_min + && chrg_step->pres_chrg_step != chip->chrg_step_nums - 1 + && chrg_step->chrg_step_cc_curr >= + chrg_list->chrg_dev[CP_MASTER]->charging_curr_min + && batt_soc < QC3P_CP_CHRG_SOC_LIMIT) { + + mmi_chrg_dbg(chip, PR_MOTO, "Enter into CHRG PUMP, " + "vbatt %d uV, " + "qc3p support %d, " + "chrg step %d, " + "chrg step cc curr %d uA, " + "CP master charging curr min %d uA\n", + vbatt_volt, + chip->qc3p_active, + chrg_step->pres_chrg_step, + chrg_step->chrg_step_cc_curr, + chrg_list->chrg_dev[CP_MASTER]->charging_curr_min); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CHRG_PUMP_ENTRY); + + } else { + mmi_chrg_dbg(chip, PR_MOTO, "Enter into PMIC switch charging, " + "the reason is : vbatt %d uV, " + "pl chrg vbatt min %d uV, " + "qc3p support %d, " + "chrg step %d\n", + vbatt_volt, chip->pl_chrg_vbatt_min, + chip->qc3p_active, + chrg_step->pres_chrg_step); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SW_ENTRY); + + } + chip->qc3p_batt_therm_cooling = false; + chip->qc3p_batt_therm_cooling_cnt= 0; + chip->qc3p_sys_therm_volt= chip->qc3p_request_volt_prev; + chip->qc3p_batt_therm_volt = chip->qc3p_request_volt_prev; + chip->qc3p_ibus_max_volt = chip->qc3p_request_volt_prev; + chip->qc3p_sys_therm_cooling = false; + chip->qc3p_sys_therm_force_pmic_chrg = false; + chip->qc3p_recovery_pmic_chrg = false; + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + break; + case PM_QC3P_STATE_SW_ENTRY: + if (chrg_list->cp_slave + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + } + + if (chrg_list->cp_master + && chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], false); + } + + if (chrg_list->chrg_dev[PMIC_SW]->charger_limited) { + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_chrg_info(chip, "Recovery PMIC-SW ichg lmt ,%d uA\n", + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + QC3P_DISABLE_CHRG_LIMIT); + chrg_list->chrg_dev[PMIC_SW]->charger_limited = false; + } + + if (!chip->dont_rerun_aicl) { + mmi_chrg_info(chip, "Do an rerun usb AICL for PMIC-SW\n"); + mmi_enable_charging(chrg_list->chrg_dev[PMIC_SW], false); + msleep(100); + mmi_enable_charging(chrg_list->chrg_dev[PMIC_SW], true); + } + chip->qc3p_request_volt = SWITCH_CHARGER_QC3P_VOLT; + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SW_LOOP); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + break; + case PM_QC3P_STATE_SW_LOOP: + if (chip->qc3p_active + && chip->cp_disable == false + && vbatt_volt > chip->pl_chrg_vbatt_min + && chrg_step->pres_chrg_step != chip->chrg_step_nums - 1 + && chrg_step->chrg_step_cc_curr >= + chrg_list->chrg_dev[CP_MASTER]->charging_curr_min + && !chip->qc3p_recovery_pmic_chrg + && !chip->qc3p_sys_therm_force_pmic_chrg + && batt_soc < QC3P_CP_CHRG_SOC_LIMIT) { + mmi_chrg_info(chip, "Enter CP, the reason is : " + "qc3p support %d, " + "vbatt %duV, chrg step %d\n", + chip->qc3p_active, + vbatt_volt, chrg_step->pres_chrg_step); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CHRG_PUMP_ENTRY); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + } else { + mmi_chrg_dbg(chip, PR_MOTO, "Continue to SW charging, " + "vbatt %d uV, ibatt %d uA\n", + vbatt_volt, ibatt_curr); + heartbeat_dely_ms = QC3P_HEARTBEAT_lOOP_WAIT_MS; + } + break; + case PM_QC3P_STATE_CHRG_PUMP_ENTRY: + mmi_chrg_info(chip,"CP master exist %d, CP slave exist %d !\n", + chrg_list->cp_master, + chrg_list->cp_slave); + if (chrg_list->cp_slave) { + mmi_chrg_info(chip,"CP slave is exist !\n"); + mmi_chrg_info(chip,"chrg step cc curr %d uA, " + "CP slave charging curr min %d uA\n", + chrg_step->chrg_step_cc_curr, + chrg_list->chrg_dev[CP_SLAVE]->charging_curr_min); + if (chrg_step->chrg_step_cc_curr >= + chrg_list->chrg_dev[CP_SLAVE]->charging_curr_min) { + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_DULE_CP_ENTRY); + } else + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_SINGLE_CP_ENTRY); + } else { + mmi_chrg_info(chip,"CP slave isn't exist !\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SINGLE_CP_ENTRY); + } + + mmi_chrg_info(chip,"Set PMIC SW FCC limits!\n"); + if (!chrg_list->chrg_dev[PMIC_SW]->charger_limited + && chrg_list->chrg_dev[PMIC_SW]->charging_curr_limited > 0) { + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + chrg_list->chrg_dev[PMIC_SW]->charging_curr_limited); + mmi_chrg_info(chip,"Set PMIC-SW ichg lmt ,%d uA\n", + chrg_list->chrg_dev[PMIC_SW]->charging_curr_limited); + chrg_list->chrg_dev[PMIC_SW]->charger_limited = true; + } + + /*Initial setup qc3p request power by the battery voltage*/ + chip->qc3p_request_volt = (2 * vbatt_volt) % 20000; + chip->qc3p_request_volt = 2 * vbatt_volt - chip->qc3p_request_volt + + chip->qc3p_volt_comp; + mmi_chrg_info(chip,"qc3p init , volt %dmV, volt comp %dmv\n", + chip->qc3p_request_volt, chip->qc3p_volt_comp); + chrg_policy_error_clear(chip, chrg_list); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + break; + case PM_QC3P_STATE_SINGLE_CP_ENTRY: + if (chrg_list->cp_slave + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_chrg_info(chip,"Disable Slave Charger Pump !\n"); + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + } + + if (chrg_list->cp_master) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], true); + mmi_chrg_info(chip,"Enable Master Charger Pump !\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_TUNNING_VOLT); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + } + break; + case PM_QC3P_STATE_DULE_CP_ENTRY: + if (chrg_list->cp_master) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], true); + mmi_chrg_info(chip,"Enable Master Charger Pump !\n"); + } + + if (chrg_list->cp_slave) { + chrg_list->cp_clave_later = true; + mmi_chrg_info(chip,"For ibus UCP, " + "delay start Slave Charger Pump in TUNNING_VOLT stage !\n"); + } + + if (chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_TUNNING_VOLT); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + } + break; + case PM_QC3P_STATE_TUNNING_VOLT: + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + if (chrg_list->cp_slave + && chrg_list->cp_clave_later + && !chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], true); + mmi_chrg_info(chip,"Enable Slave Charger Pump !\n"); + } + + if (chrg_list->cp_master + && !chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_chrg_info(chip,"CP MASTER was disabled, " + "Enter into SW directly\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SW_ENTRY); + } else if (vbatt_volt > chrg_step->chrg_step_cv_volt) { + chip->qc3p_request_volt -= chip->qc3p_volt_steps; + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_CP_CC_LOOP); + mmi_chrg_info(chip,"Duing the volt going up process, " + "the chrg step was changed," + "stop increase qc3p volt and" + " Enter into CC stage as soon!\n"); + } else if (chip->qc3p_request_volt + chip->qc3p_volt_steps + <= chip->qc3p_volt_max + && vbatt_volt < chrg_step->chrg_step_cv_volt + && ibatt_curr < ((chrg_step->pres_chrg_step == STEP_FIRST) ? + chrg_step->chrg_step_cc_curr + chip->step_first_curr_comp: + chrg_step->chrg_step_cc_curr)) { + chip->qc3p_request_volt += chip->qc3p_volt_steps; + mmi_chrg_dbg(chip, PR_MOTO, "Increase qc3p volt %d\n", + chip->qc3p_request_volt); + heartbeat_dely_ms = QC3P_HEARTBEAT_TUNNING_MS; + } else { + mmi_chrg_info(chip,"Enter into CC loop stage !\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CP_CC_LOOP); + } + + if (ibatt_curr > qc3p_batt_curr_roof) { + qc3p_batt_curr_roof = ibatt_curr; + } + if (ibatt_curr < qc3p_batt_curr_roof) + qc3p_constant_power_cnt++; + else + qc3p_constant_power_cnt = 0; + + if (qc3p_constant_power_cnt > QC3P_CONT_PWR_CNT) { + mmi_chrg_info(chip,"QC3P adapter was ready in constant power state, " + "Enter into CC loop stage !\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CP_CC_LOOP); + } + mmi_chrg_info(chip, "qc3p_constant_power_cnt %d, " + "qc3p_batt_curr_roof %d\n", + qc3p_constant_power_cnt, + qc3p_batt_curr_roof); + break; + case PM_QC3P_STATE_CP_CC_LOOP: + heartbeat_dely_ms = QC3P_HEARTBEAT_lOOP_WAIT_MS; + mmi_chrg_dbg(chip, PR_MOTO, + "Chrg CC loop, chrg_step %d, " + "vbatt %dmV, ibatt %dmA, " + "CC target curr %dmA, " + "next CV target volt %dmV\n ", + chrg_step->pres_chrg_step, + vbatt_volt, ibatt_curr, + chrg_step->chrg_step_cc_curr, + chrg_step->chrg_step_cv_volt); + if (chrg_list->cp_master + && !chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_chrg_info(chip,"CP MASTER was disabled, Enter into SW directly\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SW_ENTRY); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + goto schedule; + } + + if (!chip->qc3p_sys_therm_cooling + && !chip->qc3p_batt_therm_cooling + && qc3p_constant_power_cnt <= QC3P_CONT_PWR_CNT) { + if (ibatt_curr < chrg_step->chrg_step_cc_curr + && chip->qc3p_request_volt < chip->qc3p_volt_max + && qc3p_chrg_cc_power_tunning_cnt >= + QC3P_CC_POWER_COUNT) { + if (chip->qc3p_request_volt + chip->qc3p_volt_steps + < chip->qc3p_volt_max) { + chip->qc3p_request_volt += + chip->qc3p_volt_steps; + mmi_chrg_dbg(chip, PR_MOTO, + "Request volt increass %duV\n ", + chip->qc3p_request_volt); + } + qc3p_chrg_cc_power_tunning_cnt = 0; + }else if (ibatt_curr < chrg_step->chrg_step_cc_curr + && chip->qc3p_request_volt < chip->qc3p_volt_max) { + qc3p_chrg_cc_power_tunning_cnt++; + mmi_chrg_dbg(chip, PR_MOTO, + "Chrg CC tunning cnt %d\n", + qc3p_chrg_cc_power_tunning_cnt); + } else if (ibatt_curr > chrg_step->chrg_step_cc_curr + + QC3P_CC_CURR_DEBOUNCE) { + chip->qc3p_request_volt -= chip->qc3p_volt_steps; + mmi_chrg_dbg(chip, PR_MOTO, + "In the CC step , the ibatt is greater than CC curr, " + "Request volt decreass %duV to remain CC step\n ", + chip->qc3p_request_volt); + } else + qc3p_chrg_cc_power_tunning_cnt = 0; + + if(ibatt_curr < chrg_step->chrg_step_cc_curr) + heartbeat_dely_ms = QC3P_HEARTBEAT_SHORT_DELAY_MS; + } + + if (vbatt_volt > chrg_step->chrg_step_cv_volt) { + if (qc3p_chrg_cv_taper_tunning_cnt > + QC3P_CV_TAPPER_COUNT) { + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CP_CV_LOOP); + qc3p_chrg_cv_taper_tunning_cnt = 0; + qc3p_chrg_cv_delta_volt = QC3P_CV_DELTA_VOLT; + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + } else { + qc3p_chrg_cv_taper_tunning_cnt++; + mmi_chrg_dbg(chip, PR_MOTO, + "Chrg CV taper cnt %d, " + "chrg step cv volt %dmV, " + "vbatt %dmV\n", + qc3p_chrg_cv_taper_tunning_cnt, + chrg_step->chrg_step_cv_volt, + vbatt_volt); + } + } else + qc3p_chrg_cv_taper_tunning_cnt = 0; + + break; + case PM_QC3P_STATE_CP_CV_LOOP: + heartbeat_dely_ms = QC3P_HEARTBEAT_SHORT_DELAY_MS; + mmi_chrg_dbg(chip, PR_MOTO, + "Chrg CV loop, chrg_step %d, " + "vbatt %dmV, ibatt %dmA, " + "CV target volt %dmV, " + "CV taper curr %dmA\n ", + chrg_step->pres_chrg_step, + vbatt_volt, ibatt_curr, + chrg_step->chrg_step_cv_volt, + chrg_step->chrg_step_cv_tapper_curr); + if (chrg_list->cp_master + && !chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_chrg_info(chip,"CP MASTER was disabled, Enter into SW directly\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SW_ENTRY); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + goto schedule; + } + + if (vbatt_volt >= chrg_step->chrg_step_cv_volt + && ((!chrg_step->last_step && + ibatt_curr < chrg_step->chrg_step_cv_tapper_curr) + || ibatt_curr < chrg_list->chrg_dev[CP_MASTER]->charging_curr_min)) { + if (qc3p_chrg_cv_taper_tunning_cnt >= QC3P_CV_TAPPER_COUNT) { + if (ibatt_curr < + chrg_list->chrg_dev[CP_MASTER]->charging_curr_min) { + mmi_chrg_info(chip, "Ready quite CP chrg stage, " + "and Enter into PMIC switch chrg stage, " + "chrg step %d, ibatt %dmA\n", + chrg_step->pres_chrg_step, ibatt_curr); + mmi_find_chrg_step(chip, + chip->pres_temp_zone, vbatt_volt); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CP_QUIT); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + } else { + if (mmi_find_chrg_step(chip, + chip->pres_temp_zone, vbatt_volt)) { + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + mmi_chrg_info(chip,"Jump to next chrg step\n"); + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_CP_CC_LOOP); + } else { + mmi_chrg_info(chip,"Can't find next chrg step\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_CP_QUIT); + } + } + qc3p_chrg_cv_taper_tunning_cnt = 0; + } else { + qc3p_chrg_cv_taper_tunning_cnt++; + mmi_chrg_dbg(chip, PR_MOTO, "chrg cv taper cnt ++, %d\n", + qc3p_chrg_cv_taper_tunning_cnt); + } + + }else if (!chip->qc3p_sys_therm_cooling + && !chip->qc3p_batt_therm_cooling) { + + qc3p_chrg_cv_taper_tunning_cnt = 0; + if (vbatt_volt > chrg_step->chrg_step_cv_volt + 10000) { + if (qc3p_chrg_cv_delta_volt > 20000) + chip->qc3p_request_volt -= qc3p_chrg_cv_delta_volt; + else + chip->qc3p_request_volt -= 20000; + mmi_chrg_info(chip, + "For keeping CV stage, decrease volt %dmV, " + "cv delta volt %dmV\n", + chip->qc3p_request_volt, qc3p_chrg_cv_delta_volt); + } else if (vbatt_volt < chrg_step->chrg_step_cv_volt - 10000) { + qc3p_chrg_cv_delta_volt -= 20000; + chip->qc3p_request_volt += 20000; + mmi_chrg_info(chip, + "For keeping CV stage, increase volt %dmV, " + "cv delta volt %dmV\n", + chip->qc3p_request_volt, qc3p_chrg_cv_delta_volt); + } else { + mmi_chrg_dbg(chip, PR_MOTO, "CV loop work well, " + "keep qc3p power, volt %dmV\n", + chip->qc3p_request_volt); + } + + }else { + /*In this case, qc3p_sys_therm_cooling or qc3p_batt_therm_cooling is ture*/ + + if (vbatt_volt > chrg_step->chrg_step_cv_volt + 10000) { + if (qc3p_chrg_cv_delta_volt > 20000) + chip->qc3p_request_volt -= qc3p_chrg_cv_delta_volt; + else + chip->qc3p_request_volt -= 20000; + mmi_chrg_info(chip, + "For keeping CV stage, decrease volt %dmV, " + "cv delta volt %dmV\n", + chip->qc3p_request_volt, qc3p_chrg_cv_delta_volt); + } else { + mmi_chrg_dbg(chip, PR_MOTO, "CV loop work well, " + "keep qc3p power, volt %dmV\n", + chip->qc3p_request_volt); + } + } + + if (chrg_list->cp_slave) { + if (qc3p_quit_slave_chrg_cnt > 3 + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + mmi_chrg_info(chip,"Quit slave chrg, the reason is :ibatt %duA, " + "CP slave charging curr min %d uA\n", + ibatt_curr, + chrg_list->chrg_dev[CP_SLAVE]->charging_curr_min); + msleep(100); + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], true); + mmi_chrg_info(chip,"Restart CP master again\n"); + } + + if (ibatt_curr < + chrg_list->chrg_dev[CP_SLAVE]->charging_curr_min) + qc3p_quit_slave_chrg_cnt++; + else + qc3p_quit_slave_chrg_cnt = 0; + } + break; + case PM_QC3P_STATE_CP_QUIT: + if (chrg_list->cp_slave + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + } + + if (chrg_list->cp_master + && chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], false); + } + + chip->qc3p_batt_therm_cooling = false; + chip->qc3p_batt_therm_cooling_cnt = 0; + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_RECOVERY_SW); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + break; + case PM_QC3P_STATE_RECOVERY_SW: + heartbeat_dely_ms = QC3P_HEARTBEAT_SHORT_DELAY_MS; + if (chrg_list->chrg_dev[PMIC_SW]->charger_limited) { + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_chrg_info(chip,"Recovery PMIC-SW ichg lmt ,%d uA\n", + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + QC3P_DISABLE_CHRG_LIMIT); + chrg_list->chrg_dev[PMIC_SW]->charger_limited = false; + + if (!chip->dont_rerun_aicl) { + mmi_chrg_info(chip,"Do an rerun usb AICL for PMIC-SW\n"); + mmi_enable_charging(chrg_list->chrg_dev[PMIC_SW], false); + msleep(100); + mmi_enable_charging(chrg_list->chrg_dev[PMIC_SW], true); + } + chip->qc3p_recovery_pmic_chrg = true; + qc3p_chrg_cv_taper_tunning_cnt = 0; + } + + mmi_chrg_info(chip,"ibatt : %dmA, step cc curr : %dmA\n", + ibatt_curr, chrg_step->chrg_step_cc_curr); + if (ibatt_curr > chrg_step->chrg_step_cc_curr) { + chip->qc3p_request_volt -= QC3P_CV_DELTA_VOLT; + + mmi_chrg_dbg(chip, PR_MOTO, "Reduce qc3p volt %dmV\n ", + chip->qc3p_request_volt); + heartbeat_dely_ms = QC3P_HEARTBEAT_TUNNING_MS; + qc3p_chrg_cv_taper_tunning_cnt = 0; + } else { + qc3p_chrg_cv_taper_tunning_cnt++; + + } + + if (qc3p_chrg_cv_taper_tunning_cnt > QC3P_CV_TAPPER_COUNT){ + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SW_LOOP); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + } + break; + case PM_QC3P_STATE_STOP_CHARGE: + heartbeat_dely_ms = QC3P_HEARTBEAT_lOOP_WAIT_MS; + if (chrg_list->cp_slave + && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_SLAVE], false); + } + + if (chrg_list->cp_master + && chrg_list->chrg_dev[CP_MASTER]->charger_enabled) { + mmi_enable_charging(chrg_list->chrg_dev[CP_MASTER], false); + } + + if (chrg_list->chrg_dev[PMIC_SW]->charger_limited) { + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_chrg_info(chip,"Recovery PMIC-SW ichg lmt ,%d uA\n", + chrg_list->chrg_dev[PMIC_SW]->input_curr_setted); + mmi_set_charing_current(chrg_list->chrg_dev[PMIC_SW], + QC3P_DISABLE_CHRG_LIMIT); + chrg_list->chrg_dev[PMIC_SW]->charger_limited = false; + } + + if (chip->pres_temp_zone != ZONE_COLD + && chip->pres_temp_zone != ZONE_HOT + && chrg_list->chrg_dev[PMIC_SW]->charger_enabled + && chrg_step->chrg_step_cc_curr > 0) { + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_ENTRY); + heartbeat_dely_ms = QC3P_HEARTBEAT_NEXT_STATE_MS; + } + chip->qc3p_request_volt = SWITCH_CHARGER_QC3P_VOLT; + break; + } + +schedule: + + chip->qc3p_target_volt = min(chip->qc3p_request_volt, chip->qc3p_volt_max); + + if (chip->system_thermal_level == 0) { + chip->qc3p_sys_therm_cooling= false; + chip->qc3p_sys_therm_force_pmic_chrg = false; + } else if ((chip->system_thermal_level == chip->thermal_levels - 1) + && !chip->qc3p_sys_therm_force_pmic_chrg) { + chip->qc3p_sys_therm_cooling = true; + chip->qc3p_sys_therm_force_pmic_chrg = true; + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_SW_ENTRY); + mmi_chrg_info(chip, "Thermal is the highest, level %d, " + "Force enter into single pmic charging !\n", + chip->system_thermal_level); + + } else if (chip->system_thermal_level > 0 && + (qc3p_sm_state == PM_QC3P_STATE_CP_CC_LOOP || + qc3p_sm_state == PM_QC3P_STATE_CP_CV_LOOP)) { + + mmi_chrg_dbg(chip, PR_MOTO, "Thermal level is %d\n", + chip->system_thermal_level); + if (!chip->qc3p_sys_therm_cooling) { + chip->qc3p_sys_therm_cooling = true; + chip->qc3p_sys_therm_volt = chip->qc3p_request_volt_prev; + } + + if (ibatt_curr > + chip->thermal_mitigation[chip->system_thermal_level] + QC3P_CC_CURR_DEBOUNCE) { + if (ibatt_curr - chip->thermal_mitigation[chip->system_thermal_level] > 300000) + chip->qc3p_sys_therm_volt -= chip->qc3p_volt_steps *3; + else + chip->qc3p_sys_therm_volt -= chip->qc3p_volt_steps; + mmi_chrg_dbg(chip, PR_MOTO, "For thermal, decrease qc3 volt %d\n", + chip->qc3p_sys_therm_volt); + } else if ((ibatt_curr < + chip->thermal_mitigation[chip->system_thermal_level])) { + if (chip->thermal_mitigation[chip->system_thermal_level] - ibatt_curr > 300000) + chip->qc3p_sys_therm_volt += chip->qc3p_volt_steps *3; + else + chip->qc3p_sys_therm_volt += chip->qc3p_volt_steps; + chip->qc3p_sys_therm_volt = min(chip->qc3p_volt_max, chip->qc3p_sys_therm_volt); + mmi_chrg_dbg(chip, PR_MOTO, "For thermal, increase qc3 volt %d\n", + chip->qc3p_sys_therm_volt); + } + + heartbeat_dely_ms = QC3P_HEARTBEAT_TUNNING_MS; + } else if (chip->system_thermal_level > 0 && + chip->system_thermal_level != chip->thermal_levels - 1 && + qc3p_sm_state == PM_QC3P_STATE_SW_LOOP && + chip->qc3p_sys_therm_force_pmic_chrg) { + mmi_chrg_dbg(chip, PR_MOTO, "Try to recovery charger pump!\n"); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_ENTRY); + } + + if (chip->qc3p_sys_therm_cooling) + chip->qc3p_target_volt = min(chip->qc3p_target_volt, chip->qc3p_sys_therm_volt); + + if (chip->qc3p_batt_therm_cooling && !chip->qc3p_sys_therm_force_pmic_chrg) { + if (batt_temp > chrg_step->temp_c + COOLING_HYSTERISIS_DEGC) { + + mmi_chrg_info(chip,"Batt temp %d, Cooling loop failed, " + "force enter PM_QC3P_STATE_ENTRY " + "restart this charger process !\n", + batt_temp); + chip->qc3p_batt_therm_cooling = false; + chip->qc3p_batt_therm_cooling_cnt= 0; + mmi_find_chrg_step(chip, chip->pres_temp_zone, + vbatt_volt); + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_ENTRY); + + } else if (batt_temp > chrg_step->temp_c) { + cooling_volt = (2 * vbatt_volt) % 20000; + cooling_volt = 2 * vbatt_volt - cooling_volt + + chip->qc3p_volt_comp; + if (ibatt_curr > TYPEC_HIGH_CURRENT_UA + && chip->qc3p_batt_therm_volt > cooling_volt) { + chip->qc3p_batt_therm_volt -= QC3P_COOLING_DELTA_POWER; + mmi_chrg_info(chip, "Do chrg power cooling" + "qc3p request volt %dmA, " + "battery temp %d\n", + chip->qc3p_batt_therm_volt, batt_temp); + } else { + if (chip->qc3p_batt_therm_cooling_cnt > QC3P_COOLING_MAX_CNT) { + mmi_chrg_info(chip, "Do chrg power cooling failed" + "qc3p_batt_therm_volt %dmV" + "battery temp %d, " + "Restart PM_STATE_ENTRY !\n", + chip->qc3p_batt_therm_volt, + batt_temp); + mmi_find_chrg_step(chip, chip->pres_temp_zone, + vbatt_volt); + chip->qc3p_batt_therm_cooling = false; + chip->qc3p_batt_therm_cooling_cnt = 0; + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_ENTRY); + } else { + mmi_chrg_info(chip, "It's already the lowest cooling chrg power" + "waiting for a while, cooling cnt %d, " + "battery temp %d\n", + batt_temp, chip->qc3p_batt_therm_cooling); + chip->qc3p_batt_therm_cooling_cnt++; + } + } + } else if (batt_temp < chrg_step->temp_c - COOLING_HYSTERISIS_DEGC) { + + mmi_chrg_info(chip,"Batt temp %d, " + "Exit successfully from COOLing loop!\n", + batt_temp); + + if (qc3p_sm_state == PM_QC3P_STATE_CP_CC_LOOP) { + mmi_chrg_info(chip,"Jump into CURR tunning" + "for chrg power poerformance!\n"); + mmi_chrg_qc3p_sm_move_state(chip, + PM_QC3P_STATE_TUNNING_VOLT); + } + chip->qc3p_batt_therm_cooling = false; + chip->qc3p_batt_therm_cooling_cnt = 0; + } + heartbeat_dely_ms = QC3P_HEARTBEAT_lOOP_WAIT_MS; + } + + if (chip->qc3p_batt_therm_cooling) + chip->qc3p_target_volt = min(chip->qc3p_target_volt, chip->qc3p_batt_therm_volt); + + ibus_total_ma = chrg_list->chrg_dev[PMIC_SW]->charger_data.ibus_curr / 1000 + chrg_list->chrg_dev[CP_MASTER]->charger_data.ibus_curr; + if (chrg_list->cp_slave && chrg_list->chrg_dev[CP_SLAVE]->charger_enabled) { + ibus_total_ma += chrg_list->chrg_dev[CP_SLAVE]->charger_data.ibus_curr; + } + + if(ibus_total_ma > chip->qc3p_max_ibus_ma) { + chip->qc3p_ibus_max_volt -= 2 * chip->qc3p_volt_steps; + chip->qc3p_target_volt = min(chip->qc3p_target_volt, chip->qc3p_ibus_max_volt); + chip->qc3p_request_volt = chip->qc3p_target_volt; + mmi_chrg_info(chip,"Limit ibus current: ibus is %dmA, max allow is %dmA, ibus volt is %duV, target volt is %duV \n", + ibus_total_ma, chip->qc3p_max_ibus_ma, chip->qc3p_ibus_max_volt, chip->qc3p_target_volt); + } + + mmi_chrg_dbg(chip, PR_MOTO, "chrg sm work,%s, " + "battery soc %d, " + "battery temp %d, " + "battery current %d, " + "battery voltage %d, " + "sys therm level %d, " + "pmic therm level %d, " + "sys therm cooling %d, " + "batt therm cooling %d, " + "sys therm force pmic chrg %d, " + "recovery pmic chrg %d", + pm_qc3p_state_str[qc3p_sm_state], + batt_soc, batt_temp, + ibatt_curr, vbatt_volt, + chip->system_thermal_level, + pmic_sys_therm_level, + chip->qc3p_sys_therm_cooling, + chip->qc3p_batt_therm_cooling, + chip->qc3p_sys_therm_force_pmic_chrg, + chip->qc3p_recovery_pmic_chrg); + + mmi_chrg_dbg(chip, PR_MOTO, "qc3p request volt %dmV, " + "qc3p target volt %dmV, " + "sys therm volt %dmV, " + "batt therm volt %dmV," + "qc3p_ibus_max_volt %dmV," + "qc3p_max_ibus_ma %dmA," + "ibus total %dmA\n", + chip->qc3p_request_volt, + chip->qc3p_target_volt, + chip->qc3p_sys_therm_volt, + chip->qc3p_batt_therm_volt, + chip->qc3p_ibus_max_volt, + chip->qc3p_max_ibus_ma, + ibus_total_ma); + + if (chip->qc3p_target_volt < SWITCH_CHARGER_QC3P_VOLT) { + + if (qc3p_sm_state == PM_QC3P_STATE_TUNNING_VOLT + || qc3p_sm_state == PM_QC3P_STATE_CP_CC_LOOP + || qc3p_sm_state == PM_QC3P_STATE_CP_CV_LOOP) { + + mmi_chrg_err(chip, "%s, wrong qc3p voltage or current , " + "request qc3p voltage %d, ", + pm_qc3p_state_str[qc3p_sm_state], + chip->qc3p_target_volt); + mmi_chrg_qc3p_sm_move_state(chip, PM_QC3P_STATE_ENTRY); + } + goto skip_pd_select; + } + + rc = mmi_qc3p_set_vbus_voltage(chip, chip->qc3p_target_volt / 1000); + if (rc > 0) { + chip->qc3p_request_volt_prev = chip->qc3p_target_volt; + chip->qc3p_ibus_max_volt = chip->qc3p_target_volt; + } +skip_pd_select: + + if (heartbeat_dely_ms > 0) { + mmi_chrg_err(chip, "schedule work timer %dms\n", heartbeat_dely_ms); + schedule_delayed_work(&chip->mmi_qc3p_chrg_sm_work, + msecs_to_jiffies(heartbeat_dely_ms)); + } else { + mmi_qc3p_chrg_policy_clear(chip); + chip->sm_work_running = false; + chip->qc3p_active = false; + mmi_chrg_err(chip, "exit sm work\n"); + } + + return; +} + + diff --git a/drivers/power/mmi_parallel_charger_iio/qpnp_pmic_charger.c b/drivers/power/mmi_parallel_charger_iio/qpnp_pmic_charger.c index f9b0e118b717..7a831e37cf6d 100644 --- a/drivers/power/mmi_parallel_charger_iio/qpnp_pmic_charger.c +++ b/drivers/power/mmi_parallel_charger_iio/qpnp_pmic_charger.c @@ -87,7 +87,26 @@ static int qpnp_pmic_get_charging_current(struct mmi_charger_device *chrg, u32 * rc = power_supply_get_property(chrg->chrg_psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); if (!rc) - *uA = !!prop.intval; + *uA = prop.intval; + + return rc; +} + +static int qpnp_pmic_get_ibus(struct mmi_charger_device *chrg, u32 *uA) +{ + int rc; + static struct power_supply *usb_psy; + union power_supply_propval prop = {0,}; + + if (!usb_psy) + usb_psy = power_supply_get_by_name("usb"); + if (!usb_psy) + return -ENODEV; + + rc = power_supply_get_property(usb_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + if (!rc) + *uA = prop.intval; return rc; } @@ -130,16 +149,22 @@ static int qpnp_pmic_update_charger_status(struct mmi_charger_device *chrg) { int rc; bool value = 0; - struct power_supply *usb_psy; + static struct power_supply *usb_psy = NULL; union power_supply_propval prop = {0,}; if (!chrg->chrg_psy) return -ENODEV; + if (!usb_psy) usb_psy = power_supply_get_by_name("usb"); if (!usb_psy) return -ENODEV; + rc = power_supply_get_property(usb_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + if (!rc) + chrg->charger_data.ibus_curr= prop.intval; + rc = power_supply_get_property(chrg->chrg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop); if (!rc) @@ -190,6 +215,7 @@ struct mmi_charger_ops qpnp_pmic_charger_ops = { .enable = qpnp_pmic_enable_charging, .is_enabled = qpnp_pmic_is_charging_enabled, .get_charging_current = qpnp_pmic_get_charging_current, + .get_input_current = qpnp_pmic_get_ibus, .set_charging_current = qpnp_pmic_set_charging_current, .get_input_current_settled = qpnp_pmic_get_input_current_settled, .update_charger_status = qpnp_pmic_update_charger_status, diff --git a/drivers/power/mmi_parallel_charger_iio/sc8549_charger.c b/drivers/power/mmi_parallel_charger_iio/sc8549_charger.c index 8c94e3016de1..6b5a6fccd9fd 100644 --- a/drivers/power/mmi_parallel_charger_iio/sc8549_charger.c +++ b/drivers/power/mmi_parallel_charger_iio/sc8549_charger.c @@ -93,7 +93,21 @@ static int sc8549_get_charging_current(struct mmi_charger_device *chrg, u32 *uA) return rc; } -static int sc8549_get_input_current(struct mmi_charger_device *chrg, u32 *uA) +static int sc8549_get_vbus(struct mmi_charger_device *chrg, u32 *mv) +{ + int rc, val; + struct mmi_charger_manager *chip = dev_get_drvdata(&chrg->dev); + if (!chip) + return -ENODEV; + + rc = mmi_charger_read_iio_chan(chip, SC8549_INPUT_VOLTAGE_NOW, &val); + if (!rc) + *mv = val; + + return rc; +} + +static int sc8549_get_input_current(struct mmi_charger_device *chrg, u32 *uA) //ibus { int rc; int value; @@ -119,6 +133,11 @@ static int sc8549_update_charger_status(struct mmi_charger_device *chrg) if (!chrg->chrg_psy) return -ENODEV; + rc = power_supply_get_property(chrg->chrg_psy, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &prop); + if (!rc) + chrg->charger_data.ibus_curr= prop.intval; + rc = power_supply_get_property(chrg->chrg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop); if (!rc) @@ -197,6 +216,7 @@ struct mmi_charger_ops sc8549_charger_ops = { .enable = sc8549_enable_charging, .is_enabled = sc8549_is_charging_enabled, .get_charging_current = sc8549_get_charging_current, + .get_vbus = sc8549_get_vbus, .get_input_current = sc8549_get_input_current, .update_charger_status = sc8549_update_charger_status, .update_charger_error = sc8549_update_charger_error_status,