Loading arch/arm64/boot/dts/qcom/pmi632.dtsi +1 −1 Original line number Diff line number Diff line Loading @@ -397,7 +397,7 @@ interrupts = <0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x2 IRQ_TYPE_EDGE_RISING>, <0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x5 IRQ_TYPE_EDGE_BOTH>, Loading drivers/power/supply/qcom/qpnp-smb5.c +76 −4 Original line number Diff line number Diff line Loading @@ -95,6 +95,22 @@ static struct smb_params smb5_pmi632_params = { .step_u = 400, .set_proc = smblib_set_chg_freq, }, .aicl_5v_threshold = { .name = "AICL 5V threshold", .reg = USBIN_5V_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 4700, .step_u = 100, }, .aicl_cont_threshold = { .name = "AICL CONT threshold", .reg = USBIN_CONT_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 8800, .step_u = 100, .get_proc = smblib_get_aicl_cont_threshold, .set_proc = smblib_set_aicl_cont_threshold, }, }; static struct smb_params smb5_pm855b_params = { Loading Loading @@ -164,6 +180,22 @@ static struct smb_params smb5_pm855b_params = { .step_u = 400, .set_proc = NULL, }, .aicl_5v_threshold = { .name = "AICL 5V threshold", .reg = USBIN_5V_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 4700, .step_u = 100, }, .aicl_cont_threshold = { .name = "AICL CONT threshold", .reg = USBIN_CONT_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 1180, .step_u = 100, .get_proc = smblib_get_aicl_cont_threshold, .set_proc = smblib_set_aicl_cont_threshold, }, }; struct smb_dt_props { Loading Loading @@ -247,6 +279,7 @@ static int smb5_chg_config_init(struct smb5 *chip) break; case PMI632_SUBTYPE: chip->chg.smb_version = PMI632_SUBTYPE; chg->wa_flags |= WEAK_ADAPTER_WA; chg->param = smb5_pmi632_params; chg->use_extcon = true; chg->name = "pmi632_charger"; Loading Loading @@ -457,8 +490,9 @@ static int smb5_parse_dt(struct smb5 *chip) static int smb5_get_adc_data(struct smb_charger *chg, int channel, union power_supply_propval *val) { int rc; int rc, ret = 0; struct qpnp_vadc_result result; u8 reg; if (!chg->vadc_dev) { if (of_find_property(chg->dev->of_node, "qcom,chg-vadc", Loading @@ -484,13 +518,43 @@ static int smb5_get_adc_data(struct smb_charger *chg, int channel, switch (channel) { case USBIN_VOLTAGE: /* Store ADC channel config */ rc = smblib_read(chg, BATIF_ADC_CHANNEL_EN_REG, ®); if (rc < 0) { dev_err(chg->dev, "Couldn't read ADC config rc=%d\n", rc); return rc; } /* Disable all ADC channels except IBAT channel */ rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG, IBATT_CHANNEL_EN_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't write ADC config rc=%d\n", rc); return rc; } rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_V_DIV_16_PM5, &result); if (rc < 0) { pr_err("Failed to read USBIN_V over vadc, rc=%d\n", rc); return rc; ret = rc; goto restore; } val->intval = result.physical; restore: /* Restore ADC channel config */ rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG, reg); if (rc < 0) { dev_err(chg->dev, "Couldn't write ADC config rc=%d\n", rc); return rc; } /* If ADC read failed return ADC error */ if (ret < 0) rc = ret; break; case USBIN_CURRENT: rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_I_PM5, &result); Loading Loading @@ -1342,7 +1406,7 @@ static int smb5_batt_set_prop(struct power_supply *psy, rc = smblib_set_prop_ship_mode(chg, val); break; case POWER_SUPPLY_PROP_RERUN_AICL: rc = smblib_rerun_aicl(chg); rc = smblib_run_aicl(chg, RERUN_AICL); break; case POWER_SUPPLY_PROP_DP_DM: if (!chg->flash_active) Loading Loading @@ -1669,6 +1733,12 @@ static int smb5_init_hw(struct smb5 *chip) smblib_get_charge_param(chg, &chg->param.usb_icl, &chg->default_icl_ua); smblib_get_charge_param(chg, &chg->param.aicl_5v_threshold, &chg->default_aicl_5v_threshold_mv); chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv; smblib_get_charge_param(chg, &chg->param.aicl_cont_threshold, &chg->default_aicl_cont_threshold_mv); chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv; /* Use SW based VBUS control, disable HW autonomous mode */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, Loading Loading @@ -2154,6 +2224,8 @@ static struct smb_irq_info smb5_irqs[] = { [USBIN_UV_IRQ] = { .name = "usbin-uv", .handler = usbin_uv_irq_handler, .wake = true, .storm_data = {true, 3000, 5}, }, [USBIN_OV_IRQ] = { .name = "usbin-ov", Loading drivers/power/supply/qcom/schgm-flash.c +24 −1 Original line number Diff line number Diff line Loading @@ -152,6 +152,29 @@ int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val) return 0; } void schgm_flash_torch_priority(struct smb_charger *chg, enum torch_mode mode) { int rc; u8 reg; /* * If torch is configured in default BOOST mode, skip any update in the * mode configuration. */ if (chg->headroom_mode == FIXED_MODE) return; if ((mode != TORCH_BOOST_MODE) && (mode != TORCH_BUCK_MODE)) return; reg = mode; rc = smblib_masked_write(chg, SCHGM_TORCH_PRIORITY_CONTROL_REG, TORCH_PRIORITY_CONTROL_BIT, reg); if (rc < 0) pr_err("Couldn't configure Torch priority control rc=%d\n", rc); } int schgm_flash_init(struct smb_charger *chg) { int rc; Loading Loading @@ -195,7 +218,7 @@ int schgm_flash_init(struct smb_charger *chg) reg = (chg->headroom_mode == FIXED_MODE) ? TORCH_PRIORITY_CONTROL_BIT : 0; rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL, reg); rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL_REG, reg); if (rc < 0) { pr_err("Couldn't force 5V boost in torch mode rc=%d\n", rc); Loading drivers/power/supply/qcom/schgm-flash.h +7 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ #define SCHGM_FLASH_CONTROL_REG (SCHGM_FLASH_BASE + 0x60) #define SOC_LOW_FOR_FLASH_EN_BIT BIT(7) #define SCHGM_TORCH_PRIORITY_CONTROL (SCHGM_FLASH_BASE + 0x63) #define SCHGM_TORCH_PRIORITY_CONTROL_REG (SCHGM_FLASH_BASE + 0x63) #define TORCH_PRIORITY_CONTROL_BIT BIT(0) #define SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG (SCHGM_FLASH_BASE + 0x67) Loading @@ -45,7 +45,13 @@ #define SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG \ (SCHGM_FLASH_BASE + 0x68) enum torch_mode { TORCH_BUCK_MODE = 0, TORCH_BOOST_MODE, }; int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val); void schgm_flash_torch_priority(struct smb_charger *chg, enum torch_mode mode); int schgm_flash_init(struct smb_charger *chg); bool is_flash_active(struct smb_charger *chg); Loading drivers/power/supply/qcom/smb5-lib.c +140 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "schgm-flash.h" #include "step-chg-jeita.h" #include "storm-watch.h" #include "schgm-flash.h" #define smblib_err(chg, fmt, ...) \ pr_err("%s: %s: " fmt, chg->name, \ Loading Loading @@ -321,6 +322,25 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) return result; } #define AICL_RANGE2_MIN_MV 5600 #define AICL_RANGE2_STEP_DELTA_MV 200 #define AICL_RANGE2_OFFSET 16 int smblib_get_aicl_cont_threshold(struct smb_chg_param *param, u8 val_raw) { int base = param->min_u; u8 reg = val_raw; int step = param->step_u; if (val_raw >= AICL_RANGE2_OFFSET) { reg = val_raw - AICL_RANGE2_OFFSET; base = AICL_RANGE2_MIN_MV; step = AICL_RANGE2_STEP_DELTA_MV; } return base + (reg * step); } /******************** * REGISTER SETTERS * ********************/ Loading Loading @@ -540,6 +560,29 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, return rc; } int smblib_set_aicl_cont_threshold(struct smb_chg_param *param, int val_u, u8 *val_raw) { int base = param->min_u; int offset = 0; int step = param->step_u; if (val_u > param->max_u) val_u = param->max_u; if (val_u < param->min_u) val_u = param->min_u; if (val_u >= AICL_RANGE2_MIN_MV) { base = AICL_RANGE2_MIN_MV; step = AICL_RANGE2_STEP_DELTA_MV; offset = AICL_RANGE2_OFFSET; }; *val_raw = ((val_u - base) / step) + offset; return 0; } /******************** * HELPER FUNCTIONS * ********************/ Loading Loading @@ -961,7 +1004,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) /* Re-run AICL */ if (chg->real_charger_type != POWER_SUPPLY_TYPE_USB) rc = smblib_rerun_aicl(chg); rc = smblib_run_aicl(chg, RERUN_AICL); out: return rc; } Loading Loading @@ -1616,7 +1659,7 @@ int smblib_set_prop_input_current_limited(struct smb_charger *chg, return 0; } int smblib_rerun_aicl(struct smb_charger *chg) int smblib_run_aicl(struct smb_charger *chg, int type) { int rc; u8 stat; Loading @@ -1634,8 +1677,8 @@ int smblib_rerun_aicl(struct smb_charger *chg) smblib_dbg(chg, PR_MISC, "re-running AICL\n"); rc = smblib_masked_write(chg, AICL_CMD_REG, RERUN_AICL_BIT, RERUN_AICL_BIT); stat = (type == RERUN_AICL) ? RERUN_AICL_BIT : RESTART_AICL_BIT; rc = smblib_masked_write(chg, AICL_CMD_REG, stat, stat); if (rc < 0) smblib_err(chg, "Couldn't write to AICL_CMD_REG rc=%d\n", rc); Loading Loading @@ -2691,13 +2734,79 @@ irqreturn_t batt_psy_changed_irq_handler(int irq, void *data) return IRQ_HANDLED; } #define AICL_STEP_MV 200 #define MAX_AICL_THRESHOLD_MV 4800 irqreturn_t usbin_uv_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; struct storm_watch *wdata; int rc; smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if ((chg->wa_flags & WEAK_ADAPTER_WA) && is_storming(&irq_data->storm_data)) { if (chg->aicl_max_reached) { smblib_dbg(chg, PR_MISC, "USBIN_UV storm at max AICL threshold\n"); return IRQ_HANDLED; } smblib_dbg(chg, PR_MISC, "USBIN_UV storm at threshold %d\n", chg->aicl_5v_threshold_mv); /* suspend USBIN before updating AICL threshold */ vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, true, 0); /* delay for VASHDN deglitch */ msleep(20); if (chg->aicl_5v_threshold_mv > MAX_AICL_THRESHOLD_MV) { /* reached max AICL threshold */ chg->aicl_max_reached = true; goto unsuspend_input; } /* Increase AICL threshold by 200mV */ rc = smblib_set_charge_param(chg, &chg->param.aicl_5v_threshold, chg->aicl_5v_threshold_mv + AICL_STEP_MV); if (rc < 0) dev_err(chg->dev, "Error in setting AICL threshold rc=%d\n", rc); else chg->aicl_5v_threshold_mv += AICL_STEP_MV; rc = smblib_set_charge_param(chg, &chg->param.aicl_cont_threshold, chg->aicl_cont_threshold_mv + AICL_STEP_MV); if (rc < 0) dev_err(chg->dev, "Error in setting AICL threshold rc=%d\n", rc); else chg->aicl_cont_threshold_mv += AICL_STEP_MV; unsuspend_input: if (chg->smb_version == PMI632_SUBTYPE) schgm_flash_torch_priority(chg, TORCH_BOOST_MODE); if (chg->aicl_max_reached) { smblib_dbg(chg, PR_MISC, "Reached max AICL threshold resctricting ICL to 100mA\n"); vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, true, USBIN_100MA); smblib_run_aicl(chg, RESTART_AICL); } else { smblib_run_aicl(chg, RESTART_AICL); vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, false, 0); } wdata = &chg->irq_info[USBIN_UV_IRQ].irq_data->storm_data; reset_storm_count(wdata); } if (!chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data) return IRQ_HANDLED; Loading Loading @@ -2847,6 +2956,33 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) } } if (chg->wa_flags & WEAK_ADAPTER_WA) { chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv; chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv; smblib_set_charge_param(chg, &chg->param.aicl_5v_threshold, chg->aicl_5v_threshold_mv); smblib_set_charge_param(chg, &chg->param.aicl_cont_threshold, chg->aicl_cont_threshold_mv); chg->aicl_max_reached = false; if (chg->smb_version == PMI632_SUBTYPE) schgm_flash_torch_priority(chg, TORCH_BUCK_MODE); data = chg->irq_info[USBIN_UV_IRQ].irq_data; if (data) { wdata = &data->storm_data; reset_storm_count(wdata); } vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, false, 0); } rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); Loading Loading
arch/arm64/boot/dts/qcom/pmi632.dtsi +1 −1 Original line number Diff line number Diff line Loading @@ -397,7 +397,7 @@ interrupts = <0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x2 IRQ_TYPE_EDGE_RISING>, <0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, <0x2 0x13 0x5 IRQ_TYPE_EDGE_BOTH>, Loading
drivers/power/supply/qcom/qpnp-smb5.c +76 −4 Original line number Diff line number Diff line Loading @@ -95,6 +95,22 @@ static struct smb_params smb5_pmi632_params = { .step_u = 400, .set_proc = smblib_set_chg_freq, }, .aicl_5v_threshold = { .name = "AICL 5V threshold", .reg = USBIN_5V_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 4700, .step_u = 100, }, .aicl_cont_threshold = { .name = "AICL CONT threshold", .reg = USBIN_CONT_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 8800, .step_u = 100, .get_proc = smblib_get_aicl_cont_threshold, .set_proc = smblib_set_aicl_cont_threshold, }, }; static struct smb_params smb5_pm855b_params = { Loading Loading @@ -164,6 +180,22 @@ static struct smb_params smb5_pm855b_params = { .step_u = 400, .set_proc = NULL, }, .aicl_5v_threshold = { .name = "AICL 5V threshold", .reg = USBIN_5V_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 4700, .step_u = 100, }, .aicl_cont_threshold = { .name = "AICL CONT threshold", .reg = USBIN_CONT_AICL_THRESHOLD_REG, .min_u = 4000, .max_u = 1180, .step_u = 100, .get_proc = smblib_get_aicl_cont_threshold, .set_proc = smblib_set_aicl_cont_threshold, }, }; struct smb_dt_props { Loading Loading @@ -247,6 +279,7 @@ static int smb5_chg_config_init(struct smb5 *chip) break; case PMI632_SUBTYPE: chip->chg.smb_version = PMI632_SUBTYPE; chg->wa_flags |= WEAK_ADAPTER_WA; chg->param = smb5_pmi632_params; chg->use_extcon = true; chg->name = "pmi632_charger"; Loading Loading @@ -457,8 +490,9 @@ static int smb5_parse_dt(struct smb5 *chip) static int smb5_get_adc_data(struct smb_charger *chg, int channel, union power_supply_propval *val) { int rc; int rc, ret = 0; struct qpnp_vadc_result result; u8 reg; if (!chg->vadc_dev) { if (of_find_property(chg->dev->of_node, "qcom,chg-vadc", Loading @@ -484,13 +518,43 @@ static int smb5_get_adc_data(struct smb_charger *chg, int channel, switch (channel) { case USBIN_VOLTAGE: /* Store ADC channel config */ rc = smblib_read(chg, BATIF_ADC_CHANNEL_EN_REG, ®); if (rc < 0) { dev_err(chg->dev, "Couldn't read ADC config rc=%d\n", rc); return rc; } /* Disable all ADC channels except IBAT channel */ rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG, IBATT_CHANNEL_EN_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't write ADC config rc=%d\n", rc); return rc; } rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_V_DIV_16_PM5, &result); if (rc < 0) { pr_err("Failed to read USBIN_V over vadc, rc=%d\n", rc); return rc; ret = rc; goto restore; } val->intval = result.physical; restore: /* Restore ADC channel config */ rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG, reg); if (rc < 0) { dev_err(chg->dev, "Couldn't write ADC config rc=%d\n", rc); return rc; } /* If ADC read failed return ADC error */ if (ret < 0) rc = ret; break; case USBIN_CURRENT: rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_I_PM5, &result); Loading Loading @@ -1342,7 +1406,7 @@ static int smb5_batt_set_prop(struct power_supply *psy, rc = smblib_set_prop_ship_mode(chg, val); break; case POWER_SUPPLY_PROP_RERUN_AICL: rc = smblib_rerun_aicl(chg); rc = smblib_run_aicl(chg, RERUN_AICL); break; case POWER_SUPPLY_PROP_DP_DM: if (!chg->flash_active) Loading Loading @@ -1669,6 +1733,12 @@ static int smb5_init_hw(struct smb5 *chip) smblib_get_charge_param(chg, &chg->param.usb_icl, &chg->default_icl_ua); smblib_get_charge_param(chg, &chg->param.aicl_5v_threshold, &chg->default_aicl_5v_threshold_mv); chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv; smblib_get_charge_param(chg, &chg->param.aicl_cont_threshold, &chg->default_aicl_cont_threshold_mv); chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv; /* Use SW based VBUS control, disable HW autonomous mode */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, Loading Loading @@ -2154,6 +2224,8 @@ static struct smb_irq_info smb5_irqs[] = { [USBIN_UV_IRQ] = { .name = "usbin-uv", .handler = usbin_uv_irq_handler, .wake = true, .storm_data = {true, 3000, 5}, }, [USBIN_OV_IRQ] = { .name = "usbin-ov", Loading
drivers/power/supply/qcom/schgm-flash.c +24 −1 Original line number Diff line number Diff line Loading @@ -152,6 +152,29 @@ int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val) return 0; } void schgm_flash_torch_priority(struct smb_charger *chg, enum torch_mode mode) { int rc; u8 reg; /* * If torch is configured in default BOOST mode, skip any update in the * mode configuration. */ if (chg->headroom_mode == FIXED_MODE) return; if ((mode != TORCH_BOOST_MODE) && (mode != TORCH_BUCK_MODE)) return; reg = mode; rc = smblib_masked_write(chg, SCHGM_TORCH_PRIORITY_CONTROL_REG, TORCH_PRIORITY_CONTROL_BIT, reg); if (rc < 0) pr_err("Couldn't configure Torch priority control rc=%d\n", rc); } int schgm_flash_init(struct smb_charger *chg) { int rc; Loading Loading @@ -195,7 +218,7 @@ int schgm_flash_init(struct smb_charger *chg) reg = (chg->headroom_mode == FIXED_MODE) ? TORCH_PRIORITY_CONTROL_BIT : 0; rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL, reg); rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL_REG, reg); if (rc < 0) { pr_err("Couldn't force 5V boost in torch mode rc=%d\n", rc); Loading
drivers/power/supply/qcom/schgm-flash.h +7 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ #define SCHGM_FLASH_CONTROL_REG (SCHGM_FLASH_BASE + 0x60) #define SOC_LOW_FOR_FLASH_EN_BIT BIT(7) #define SCHGM_TORCH_PRIORITY_CONTROL (SCHGM_FLASH_BASE + 0x63) #define SCHGM_TORCH_PRIORITY_CONTROL_REG (SCHGM_FLASH_BASE + 0x63) #define TORCH_PRIORITY_CONTROL_BIT BIT(0) #define SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG (SCHGM_FLASH_BASE + 0x67) Loading @@ -45,7 +45,13 @@ #define SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG \ (SCHGM_FLASH_BASE + 0x68) enum torch_mode { TORCH_BUCK_MODE = 0, TORCH_BOOST_MODE, }; int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val); void schgm_flash_torch_priority(struct smb_charger *chg, enum torch_mode mode); int schgm_flash_init(struct smb_charger *chg); bool is_flash_active(struct smb_charger *chg); Loading
drivers/power/supply/qcom/smb5-lib.c +140 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "schgm-flash.h" #include "step-chg-jeita.h" #include "storm-watch.h" #include "schgm-flash.h" #define smblib_err(chg, fmt, ...) \ pr_err("%s: %s: " fmt, chg->name, \ Loading Loading @@ -321,6 +322,25 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) return result; } #define AICL_RANGE2_MIN_MV 5600 #define AICL_RANGE2_STEP_DELTA_MV 200 #define AICL_RANGE2_OFFSET 16 int smblib_get_aicl_cont_threshold(struct smb_chg_param *param, u8 val_raw) { int base = param->min_u; u8 reg = val_raw; int step = param->step_u; if (val_raw >= AICL_RANGE2_OFFSET) { reg = val_raw - AICL_RANGE2_OFFSET; base = AICL_RANGE2_MIN_MV; step = AICL_RANGE2_STEP_DELTA_MV; } return base + (reg * step); } /******************** * REGISTER SETTERS * ********************/ Loading Loading @@ -540,6 +560,29 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, return rc; } int smblib_set_aicl_cont_threshold(struct smb_chg_param *param, int val_u, u8 *val_raw) { int base = param->min_u; int offset = 0; int step = param->step_u; if (val_u > param->max_u) val_u = param->max_u; if (val_u < param->min_u) val_u = param->min_u; if (val_u >= AICL_RANGE2_MIN_MV) { base = AICL_RANGE2_MIN_MV; step = AICL_RANGE2_STEP_DELTA_MV; offset = AICL_RANGE2_OFFSET; }; *val_raw = ((val_u - base) / step) + offset; return 0; } /******************** * HELPER FUNCTIONS * ********************/ Loading Loading @@ -961,7 +1004,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) /* Re-run AICL */ if (chg->real_charger_type != POWER_SUPPLY_TYPE_USB) rc = smblib_rerun_aicl(chg); rc = smblib_run_aicl(chg, RERUN_AICL); out: return rc; } Loading Loading @@ -1616,7 +1659,7 @@ int smblib_set_prop_input_current_limited(struct smb_charger *chg, return 0; } int smblib_rerun_aicl(struct smb_charger *chg) int smblib_run_aicl(struct smb_charger *chg, int type) { int rc; u8 stat; Loading @@ -1634,8 +1677,8 @@ int smblib_rerun_aicl(struct smb_charger *chg) smblib_dbg(chg, PR_MISC, "re-running AICL\n"); rc = smblib_masked_write(chg, AICL_CMD_REG, RERUN_AICL_BIT, RERUN_AICL_BIT); stat = (type == RERUN_AICL) ? RERUN_AICL_BIT : RESTART_AICL_BIT; rc = smblib_masked_write(chg, AICL_CMD_REG, stat, stat); if (rc < 0) smblib_err(chg, "Couldn't write to AICL_CMD_REG rc=%d\n", rc); Loading Loading @@ -2691,13 +2734,79 @@ irqreturn_t batt_psy_changed_irq_handler(int irq, void *data) return IRQ_HANDLED; } #define AICL_STEP_MV 200 #define MAX_AICL_THRESHOLD_MV 4800 irqreturn_t usbin_uv_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; struct storm_watch *wdata; int rc; smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if ((chg->wa_flags & WEAK_ADAPTER_WA) && is_storming(&irq_data->storm_data)) { if (chg->aicl_max_reached) { smblib_dbg(chg, PR_MISC, "USBIN_UV storm at max AICL threshold\n"); return IRQ_HANDLED; } smblib_dbg(chg, PR_MISC, "USBIN_UV storm at threshold %d\n", chg->aicl_5v_threshold_mv); /* suspend USBIN before updating AICL threshold */ vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, true, 0); /* delay for VASHDN deglitch */ msleep(20); if (chg->aicl_5v_threshold_mv > MAX_AICL_THRESHOLD_MV) { /* reached max AICL threshold */ chg->aicl_max_reached = true; goto unsuspend_input; } /* Increase AICL threshold by 200mV */ rc = smblib_set_charge_param(chg, &chg->param.aicl_5v_threshold, chg->aicl_5v_threshold_mv + AICL_STEP_MV); if (rc < 0) dev_err(chg->dev, "Error in setting AICL threshold rc=%d\n", rc); else chg->aicl_5v_threshold_mv += AICL_STEP_MV; rc = smblib_set_charge_param(chg, &chg->param.aicl_cont_threshold, chg->aicl_cont_threshold_mv + AICL_STEP_MV); if (rc < 0) dev_err(chg->dev, "Error in setting AICL threshold rc=%d\n", rc); else chg->aicl_cont_threshold_mv += AICL_STEP_MV; unsuspend_input: if (chg->smb_version == PMI632_SUBTYPE) schgm_flash_torch_priority(chg, TORCH_BOOST_MODE); if (chg->aicl_max_reached) { smblib_dbg(chg, PR_MISC, "Reached max AICL threshold resctricting ICL to 100mA\n"); vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, true, USBIN_100MA); smblib_run_aicl(chg, RESTART_AICL); } else { smblib_run_aicl(chg, RESTART_AICL); vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, false, 0); } wdata = &chg->irq_info[USBIN_UV_IRQ].irq_data->storm_data; reset_storm_count(wdata); } if (!chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data) return IRQ_HANDLED; Loading Loading @@ -2847,6 +2956,33 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) } } if (chg->wa_flags & WEAK_ADAPTER_WA) { chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv; chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv; smblib_set_charge_param(chg, &chg->param.aicl_5v_threshold, chg->aicl_5v_threshold_mv); smblib_set_charge_param(chg, &chg->param.aicl_cont_threshold, chg->aicl_cont_threshold_mv); chg->aicl_max_reached = false; if (chg->smb_version == PMI632_SUBTYPE) schgm_flash_torch_priority(chg, TORCH_BUCK_MODE); data = chg->irq_info[USBIN_UV_IRQ].irq_data; if (data) { wdata = &data->storm_data; reset_storm_count(wdata); } vote(chg->usb_icl_votable, AICL_THRESHOLD_VOTER, false, 0); } rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); Loading