diff options
| -rw-r--r-- | drivers/power/supply/qcom/qpnp-smbcharger.c | 714 |
1 files changed, 478 insertions, 236 deletions
diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index a2863dcf7389..a31d4d0cb198 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -144,6 +144,7 @@ struct smbchg_chip { bool vbat_above_headroom; bool force_aicl_rerun; bool hvdcp3_supported; + bool allow_hvdcp3_detection; bool restricted_charging; bool skip_usb_suspend_for_fake_battery; bool hvdcp_not_supported; @@ -175,6 +176,7 @@ struct smbchg_chip { int n_vbat_samples; /* status variables */ + int max_pulse_allowed; int wake_reasons; int previous_soc; int usb_online; @@ -286,7 +288,7 @@ struct smbchg_chip { struct votable *hw_aicl_rerun_disable_votable; struct votable *hw_aicl_rerun_enable_indirect_votable; struct votable *aicl_deglitch_short_votable; - + struct votable *hvdcp_enable_votable; /* extcon for VBUS / ID notification to USB */ struct extcon_dev *extcon; }; @@ -351,6 +353,7 @@ enum wake_reason { #define WEAK_CHARGER_ICL_VOTER "WEAK_CHARGER_ICL_VOTER" #define SW_AICL_ICL_VOTER "SW_AICL_ICL_VOTER" #define CHG_SUSPEND_WORKAROUND_ICL_VOTER "CHG_SUSPEND_WORKAROUND_ICL_VOTER" +#define SHUTDOWN_WORKAROUND_ICL_VOTER "SHUTDOWN_WORKAROUND_ICL_VOTER" /* USB SUSPEND VOTERS */ /* userspace has suspended charging altogether */ @@ -411,6 +414,10 @@ enum wake_reason { "VARB_WRKARND_SHORT_DEGLITCH_VOTER" /* QC 2.0 */ #define HVDCP_SHORT_DEGLITCH_VOTER "HVDCP_SHORT_DEGLITCH_VOTER" +/* Hvdcp enable voters*/ +#define HVDCP_PMIC_VOTER "HVDCP_PMIC_VOTER" +#define HVDCP_OTG_VOTER "HVDCP_OTG_VOTER" +#define HVDCP_PULSING_VOTER "HVDCP_PULSING_VOTER" static const unsigned int smbchg_extcon_cable[] = { EXTCON_USB, @@ -420,61 +427,61 @@ static const unsigned int smbchg_extcon_cable[] = { static int smbchg_debug_mask; module_param_named( - debug_mask, smbchg_debug_mask, int, S_IRUSR | S_IWUSR + debug_mask, smbchg_debug_mask, int, 00600 ); static int smbchg_parallel_en = 1; module_param_named( - parallel_en, smbchg_parallel_en, int, S_IRUSR | S_IWUSR + parallel_en, smbchg_parallel_en, int, 00600 ); static int smbchg_main_chg_fcc_percent = 50; module_param_named( main_chg_fcc_percent, smbchg_main_chg_fcc_percent, - int, S_IRUSR | S_IWUSR + int, 00600 ); static int smbchg_main_chg_icl_percent = 60; module_param_named( main_chg_icl_percent, smbchg_main_chg_icl_percent, - int, S_IRUSR | S_IWUSR + int, 00600 ); static int smbchg_default_hvdcp_icl_ma = 1800; module_param_named( default_hvdcp_icl_ma, smbchg_default_hvdcp_icl_ma, - int, S_IRUSR | S_IWUSR + int, 00600 ); static int smbchg_default_hvdcp3_icl_ma = 3000; module_param_named( default_hvdcp3_icl_ma, smbchg_default_hvdcp3_icl_ma, - int, S_IRUSR | S_IWUSR + int, 00600 ); static int smbchg_default_dcp_icl_ma = 1800; module_param_named( default_dcp_icl_ma, smbchg_default_dcp_icl_ma, - int, S_IRUSR | S_IWUSR + int, 00600 ); static int wipower_dyn_icl_en; module_param_named( dynamic_icl_wipower_en, wipower_dyn_icl_en, - int, S_IRUSR | S_IWUSR + int, 00600 ); static int wipower_dcin_interval = ADC_MEAS1_INTERVAL_2P0MS; module_param_named( wipower_dcin_interval, wipower_dcin_interval, - int, S_IRUSR | S_IWUSR + int, 00600 ); #define WIPOWER_DEFAULT_HYSTERISIS_UV 250000 static int wipower_dcin_hyst_uv = WIPOWER_DEFAULT_HYSTERISIS_UV; module_param_named( wipower_dcin_hyst_uv, wipower_dcin_hyst_uv, - int, S_IRUSR | S_IWUSR + int, 00600 ); #define pr_smb(reason, fmt, ...) \ @@ -625,6 +632,18 @@ static void smbchg_relax(struct smbchg_chip *chip, int reason) mutex_unlock(&chip->pm_lock); }; +static bool is_bms_psy_present(struct smbchg_chip *chip) +{ + if (chip->bms_psy) + return true; + + if (chip->bms_psy_name) + chip->bms_psy = power_supply_get_by_name( + (char *)chip->bms_psy_name); + + return chip->bms_psy ? true : false; +} + enum pwr_path_type { UNKNOWN = 0, PWR_PATH_BATTERY = 1, @@ -804,6 +823,7 @@ static char *usb_type_str[] = { static int get_type(u8 type_reg) { unsigned long type = type_reg; + type >>= TYPE_BITS_OFFSET; return find_first_bit(&type, N_TYPE_BITS); } @@ -1059,6 +1079,33 @@ static int get_prop_batt_current_now(struct smbchg_chip *chip) return ua; } +#define DEFAULT_BATT_RESISTANCE_ID 0 +static int get_prop_batt_resistance_id(struct smbchg_chip *chip) +{ + int rbatt, rc; + + rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_RESISTANCE_ID, + &rbatt); + if (rc) { + pr_smb(PR_STATUS, "Couldn't get resistance id rc = %d\n", rc); + rbatt = DEFAULT_BATT_RESISTANCE_ID; + } + return rbatt; +} + +#define DEFAULT_BATT_FULL_CHG_CAPACITY 0 +static int get_prop_batt_full_charge(struct smbchg_chip *chip) +{ + int bfc, rc; + + rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_CHARGE_FULL, &bfc); + if (rc) { + pr_smb(PR_STATUS, "Couldn't get charge_full rc = %d\n", rc); + bfc = DEFAULT_BATT_FULL_CHG_CAPACITY; + } + return bfc; +} + #define DEFAULT_BATT_VOLTAGE_NOW 0 static int get_prop_batt_voltage_now(struct smbchg_chip *chip) { @@ -1485,6 +1532,47 @@ static struct power_supply *get_parallel_psy(struct smbchg_chip *chip) return chip->parallel.psy; } +static int smbchg_request_dpdm(struct smbchg_chip *chip, bool enable) +{ + int rc = 0; + + /* fetch the DPDM regulator */ + if (!chip->dpdm_reg && of_get_property(chip->dev->of_node, + "dpdm-supply", NULL)) { + chip->dpdm_reg = devm_regulator_get(chip->dev, "dpdm"); + if (IS_ERR(chip->dpdm_reg)) { + rc = PTR_ERR(chip->dpdm_reg); + dev_err(chip->dev, "Couldn't get dpdm regulator rc=%d\n", + rc); + chip->dpdm_reg = NULL; + return rc; + } + } + + if (!chip->dpdm_reg) + return -ENODEV; + + if (enable) { + if (!regulator_is_enabled(chip->dpdm_reg)) { + pr_smb(PR_STATUS, "enabling DPDM regulator\n"); + rc = regulator_enable(chip->dpdm_reg); + if (rc < 0) + dev_err(chip->dev, "Couldn't enable dpdm regulator rc=%d\n", + rc); + } + } else { + if (regulator_is_enabled(chip->dpdm_reg)) { + pr_smb(PR_STATUS, "disabling DPDM regulator\n"); + rc = regulator_disable(chip->dpdm_reg); + if (rc < 0) + dev_err(chip->dev, "Couldn't disable dpdm regulator rc=%d\n", + rc); + } + } + + return rc; +} + static void smbchg_usb_update_online_work(struct work_struct *work) { struct smbchg_chip *chip = container_of(work, @@ -1849,6 +1937,22 @@ static bool smbchg_is_usbin_active_pwr_src(struct smbchg_chip *chip) && (reg & USBIN_ACTIVE_PWR_SRC_BIT); } +static void smbchg_detect_parallel_charger(struct smbchg_chip *chip) +{ + int rc; + struct power_supply *parallel_psy = get_parallel_psy(chip); + union power_supply_propval pval = {0, }; + + if (parallel_psy) { + pval.intval = true; + rc = power_supply_set_property(parallel_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + chip->parallel_charger_detected = rc ? false : true; + if (rc) + pr_debug("parallel-charger absent rc=%d\n", rc); + } +} + static int smbchg_parallel_usb_charging_en(struct smbchg_chip *chip, bool en) { struct power_supply *parallel_psy = get_parallel_psy(chip); @@ -1874,6 +1978,7 @@ static int smbchg_sw_esr_pulse_en(struct smbchg_chip *chip, bool en) return 0; } + fg_current_now = abs(fg_current_now) / 1000; icl_ma = max(chip->iterm_ma + ESR_PULSE_CURRENT_DELTA_MA, fg_current_now - ESR_PULSE_CURRENT_DELTA_MA); rc = vote(chip->fcc_votable, ESR_PULSE_FCC_VOTER, en, icl_ma); @@ -1985,7 +2090,8 @@ static void smbchg_parallel_usb_taper(struct smbchg_chip *chip) int parallel_fcc_ma, tries = 0; u8 reg = 0; - if (!parallel_psy || !chip->parallel_charger_detected) + smbchg_detect_parallel_charger(chip); + if (!chip->parallel_charger_detected) return; smbchg_stay_awake(chip, PM_PARALLEL_TAPER); @@ -2121,8 +2227,6 @@ static void smbchg_parallel_usb_enable(struct smbchg_chip *chip, supplied_parallel_fcc_ma); chip->parallel.enabled_once = true; - - return; } static bool smbchg_is_parallel_usb_ok(struct smbchg_chip *chip, @@ -2406,6 +2510,27 @@ static int dc_suspend_vote_cb(struct votable *votable, return rc; } +#define HVDCP_EN_BIT BIT(3) +static int smbchg_hvdcp_enable_cb(struct votable *votable, + void *data, + int enable, + const char *client) +{ + int rc = 0; + struct smbchg_chip *chip = data; + + pr_err("smbchg_hvdcp_enable_cb HVDCP %s\n", + enable ? "enabled" : "disabled"); + rc = smbchg_sec_masked_write(chip, + chip->usb_chgpth_base + CHGPTH_CFG, + HVDCP_EN_BIT, enable ? HVDCP_EN_BIT : 0); + if (rc < 0) + dev_err(chip->dev, "Couldn't %s HVDCP rc=%d\n", + enable ? "enable" : "disable", rc); + + return rc; +} + static int set_fastchg_current_vote_cb(struct votable *votable, void *data, int fcc_ma, @@ -3635,17 +3760,11 @@ static void check_battery_type(struct smbchg_chip *chip) static void smbchg_external_power_changed(struct power_supply *psy) { struct smbchg_chip *chip = power_supply_get_drvdata(psy); - union power_supply_propval prop = {0,}; - int rc, current_limit = 0, soc; - enum power_supply_type usb_supply_type; - char *usb_type_name = "null"; - - if (chip->bms_psy_name) - chip->bms_psy = - power_supply_get_by_name((char *)chip->bms_psy_name); + int rc, soc; smbchg_aicl_deglitch_wa_check(chip); - if (chip->bms_psy) { + + if (is_bms_psy_present(chip)) { check_battery_type(chip); soc = get_prop_batt_capacity(chip); if (chip->previous_soc != soc) { @@ -3660,37 +3779,8 @@ static void smbchg_external_power_changed(struct power_supply *psy) rc); } - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop); - if (rc == 0) - vote(chip->usb_suspend_votable, POWER_SUPPLY_EN_VOTER, - !prop.intval, 0); - - current_limit = chip->usb_current_max / 1000; - - /* Override if type-c charger used */ - if (chip->typec_current_ma > 500 && - current_limit < chip->typec_current_ma) - current_limit = chip->typec_current_ma; - - read_usb_type(chip, &usb_type_name, &usb_supply_type); - - if (usb_supply_type != POWER_SUPPLY_TYPE_USB) - goto skip_current_for_non_sdp; - - pr_smb(PR_MISC, "usb type = %s current_limit = %d\n", - usb_type_name, current_limit); - - rc = vote(chip->usb_icl_votable, PSY_ICL_VOTER, true, - current_limit); - if (rc < 0) - pr_err("Couldn't update USB PSY ICL vote rc=%d\n", rc); - -skip_current_for_non_sdp: + /* adjust vfloat */ smbchg_vfloat_adjust_check(chip); - - if (chip->batt_psy) - power_supply_changed(chip->batt_psy); } static int smbchg_otg_regulator_enable(struct regulator_dev *rdev) @@ -3766,7 +3856,6 @@ struct regulator_ops smbchg_otg_reg_ops = { #define USBIN_ADAPTER_9V 0x3 #define USBIN_ADAPTER_5V_9V_CONT 0x2 #define USBIN_ADAPTER_5V_UNREGULATED_9V 0x5 -#define HVDCP_EN_BIT BIT(3) static int smbchg_external_otg_regulator_enable(struct regulator_dev *rdev) { int rc = 0; @@ -3790,9 +3879,7 @@ static int smbchg_external_otg_regulator_enable(struct regulator_dev *rdev) * allowance to 9V, so that the audio boost operating in reverse never * gets detected as a valid input */ - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, 0); + rc = vote(chip->hvdcp_enable_votable, HVDCP_OTG_VOTER, true, 0); if (rc < 0) { dev_err(chip->dev, "Couldn't disable HVDCP rc=%d\n", rc); return rc; @@ -3826,9 +3913,7 @@ static int smbchg_external_otg_regulator_disable(struct regulator_dev *rdev) * value in order to allow normal USBs to be recognized as a valid * input. */ - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, HVDCP_EN_BIT); + rc = vote(chip->hvdcp_enable_votable, HVDCP_OTG_VOTER, false, 1); if (rc < 0) { dev_err(chip->dev, "Couldn't enable HVDCP rc=%d\n", rc); return rc; @@ -3958,6 +4043,11 @@ static void smbchg_chg_led_brightness_set(struct led_classdev *cdev, u8 reg; int rc; + if (!is_bms_psy_present(chip)) { + dev_err(chip->dev, "Couldn't access bms psy\n"); + return; + } + reg = (value > LED_OFF) ? CHG_LED_ON << CHG_LED_SHIFT : CHG_LED_OFF << CHG_LED_SHIFT; pval.intval = value > LED_OFF ? 1 : 0; @@ -4005,6 +4095,11 @@ static void smbchg_chg_led_blink_set(struct smbchg_chip *chip, u8 reg; int rc; + if (!is_bms_psy_present(chip)) { + dev_err(chip->dev, "Couldn't access bms psy\n"); + return; + } + pval.intval = (blinking == 0) ? 0 : 1; power_supply_set_property(chip->bms_psy, POWER_SUPPLY_PROP_HI_POWER, &pval); @@ -4013,11 +4108,11 @@ static void smbchg_chg_led_blink_set(struct smbchg_chip *chip, reg = CHG_LED_OFF << CHG_LED_SHIFT; } else { if (blinking == 1) - reg = LED_BLINKING_PATTERN1 << CHG_LED_SHIFT; - else if (blinking == 2) reg = LED_BLINKING_PATTERN2 << CHG_LED_SHIFT; - else + else if (blinking == 2) reg = LED_BLINKING_PATTERN1 << CHG_LED_SHIFT; + else + reg = LED_BLINKING_PATTERN2 << CHG_LED_SHIFT; } rc = smbchg_sec_masked_write(chip, @@ -4127,7 +4222,7 @@ static int smbchg_trim_add_steps(int prev_trim, int delta_steps) else if (scale_code > CENTER_TRIM_CODE) linear_scale = scale_code - (CENTER_TRIM_CODE + 1); - /* check if we can accomodate delta steps with just the offset */ + /* check if we can accommodate delta steps with just the offset */ if (linear_offset + delta_steps >= 0 && linear_offset + delta_steps <= MAX_LIN_CODE) { linear_offset += delta_steps; @@ -4317,7 +4412,6 @@ stop: reschedule: schedule_delayed_work(&chip->vfloat_adjust_work, msecs_to_jiffies(VFLOAT_RESAMPLE_DELAY_MS)); - return; } static int smbchg_charging_status_change(struct smbchg_chip *chip) @@ -4407,9 +4501,26 @@ static int smbchg_change_usb_supply_type(struct smbchg_chip *chip, goto out; } - /* otherwise if it is unknown, set type after the vote */ - if (type == POWER_SUPPLY_TYPE_UNKNOWN) + /* otherwise if it is unknown, set type after removing the vote */ + if (type == POWER_SUPPLY_TYPE_UNKNOWN) { + rc = vote(chip->usb_icl_votable, PSY_ICL_VOTER, true, 0); + if (rc < 0) + pr_err("Couldn't vote for new USB ICL rc=%d\n", rc); chip->usb_supply_type = type; + } + /* + * Update TYPE property to DCP for HVDCP/HVDCP3 charger types + * so that they can be recongized as AC chargers by healthd. + * Don't report UNKNOWN charger type to prevent healthd missing + * detecting this power_supply status change. + */ + if (chip->usb_supply_type == POWER_SUPPLY_TYPE_USB_HVDCP_3 + || chip->usb_supply_type == POWER_SUPPLY_TYPE_USB_HVDCP) + chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB_DCP; + else if (chip->usb_supply_type == POWER_SUPPLY_TYPE_UNKNOWN) + chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB; + else + chip->usb_psy_d.type = chip->usb_supply_type; if (!chip->skip_usb_notification) power_supply_changed(chip->usb_psy); @@ -4507,8 +4618,11 @@ static int set_usb_psy_dp_dm(struct smbchg_chip *chip, int state) if (!rc && !(reg & USBIN_UV_BIT) && !(reg & USBIN_SRC_DET_BIT)) { pr_smb(PR_MISC, "overwriting state = %d with %d\n", state, POWER_SUPPLY_DP_DM_DPF_DMF); - if (chip->dpdm_reg && !regulator_is_enabled(chip->dpdm_reg)) - return regulator_enable(chip->dpdm_reg); + rc = smbchg_request_dpdm(chip, true); + if (rc < 0) { + pr_err("Couldn't enable DP/DM for pulsing rc=%d\n", rc); + return rc; + } } pr_smb(PR_MISC, "setting usb psy dp dm = %d\n", state); pval.intval = state; @@ -4523,11 +4637,6 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) { int rc; - pr_smb(PR_MISC, "Retracting HVDCP vote for ICL\n"); - rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, false, 0); - if (rc < 0) - pr_err("Couldn't retract HVDCP ICL vote rc=%d\n", rc); - /* switch to 9V HVDCP */ rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_9V); @@ -4535,9 +4644,7 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) pr_err("Couldn't configure HVDCP 9V rc=%d\n", rc); /* enable HVDCP */ - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, HVDCP_EN_BIT); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, false, 1); if (rc < 0) pr_err("Couldn't enable HVDCP rc=%d\n", rc); @@ -4562,6 +4669,19 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) chip->hvdcp_3_det_ignore_uv = false; chip->pulse_cnt = 0; + + if ((chip->schg_version == QPNP_SCHG_LITE) + && is_hvdcp_present(chip)) { + pr_smb(PR_MISC, "Forcing 9V HVDCP 2.0\n"); + rc = force_9v_hvdcp(chip); + if (rc) + pr_err("Failed to force 9V HVDCP=%d\n", rc); + } + + pr_smb(PR_MISC, "Retracting HVDCP vote for ICL\n"); + rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, false, 0); + if (rc < 0) + pr_err("Couldn't retract HVDCP ICL vote rc=%d\n", rc); } #define RESTRICTED_CHG_FCC_PERCENT 50 @@ -4603,10 +4723,12 @@ static void handle_usb_removal(struct smbchg_chip *chip) /* Clear typec current status */ if (chip->typec_psy) chip->typec_current_ma = 0; + /* cancel/wait for hvdcp pending work if any */ + cancel_delayed_work_sync(&chip->hvdcp_det_work); + smbchg_relax(chip, PM_DETECT_HVDCP); smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN); extcon_set_cable_state_(chip->extcon, EXTCON_USB, chip->usb_present); - if (chip->dpdm_reg) - regulator_disable(chip->dpdm_reg); + smbchg_request_dpdm(chip, false); schedule_work(&chip->usb_set_online_work); pr_smb(PR_MISC, "setting usb psy health UNKNOWN\n"); @@ -4655,8 +4777,6 @@ static bool is_usbin_uv_high(struct smbchg_chip *chip) #define HVDCP_NOTIFY_MS 2500 static void handle_usb_insertion(struct smbchg_chip *chip) { - struct power_supply *parallel_psy = get_parallel_psy(chip); - union power_supply_propval pval = {0, }; enum power_supply_type usb_supply_type; int rc; char *usb_type_name = "null"; @@ -4703,14 +4823,7 @@ static void handle_usb_insertion(struct smbchg_chip *chip) msecs_to_jiffies(HVDCP_NOTIFY_MS)); } - if (parallel_psy) { - pval.intval = true; - rc = power_supply_set_property(parallel_psy, - POWER_SUPPLY_PROP_PRESENT, &pval); - chip->parallel_charger_detected = rc ? false : true; - if (rc) - pr_debug("parallel-charger absent rc=%d\n", rc); - } + smbchg_detect_parallel_charger(chip); if (chip->parallel.avail && chip->aicl_done_irq && !chip->enable_aicl_wake) { @@ -4957,7 +5070,7 @@ static int wait_for_src_detect(struct smbchg_chip *chip, bool high) if (high == src_detect) return 0; - pr_err("src detect didnt go to a %s state, still at %s, tries = %d, rc = %d\n", + pr_err("src detect didn't go to a %s state, still at %s, tries = %d, rc = %d\n", high ? "risen" : "lowered", src_detect ? "high" : "low", tries, rc); @@ -5023,6 +5136,30 @@ static int fake_insertion_removal(struct smbchg_chip *chip, bool insertion) return 0; } +static void smbchg_handle_hvdcp3_disable(struct smbchg_chip *chip) +{ + enum power_supply_type usb_supply_type; + char *usb_type_name = "NULL"; + + if (chip->allow_hvdcp3_detection) + return; + + chip->pulse_cnt = 0; + + if (is_hvdcp_present(chip)) { + smbchg_change_usb_supply_type(chip, + POWER_SUPPLY_TYPE_USB_HVDCP); + } else if (is_usb_present(chip)) { + read_usb_type(chip, &usb_type_name, &usb_supply_type); + smbchg_change_usb_supply_type(chip, usb_supply_type); + if (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP) + schedule_delayed_work(&chip->hvdcp_det_work, + msecs_to_jiffies(HVDCP_NOTIFY_MS)); + } else { + smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN); + } +} + static int smbchg_prepare_for_pulsing(struct smbchg_chip *chip) { int rc = 0; @@ -5050,8 +5187,7 @@ static int smbchg_prepare_for_pulsing(struct smbchg_chip *chip) /* disable HVDCP */ pr_smb(PR_MISC, "Disable HVDCP\n"); - rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, 0); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, true, 0); if (rc < 0) { pr_err("Couldn't disable HVDCP rc=%d\n", rc); goto out; @@ -5142,8 +5278,7 @@ static int smbchg_unprepare_for_pulsing(struct smbchg_chip *chip) { int rc = 0; - if (chip->dpdm_reg && !regulator_is_enabled(chip->dpdm_reg)) - rc = regulator_enable(chip->dpdm_reg); + rc = smbchg_request_dpdm(chip, true); if (rc < 0) { pr_err("Couldn't enable DP/DM for pulsing rc=%d\n", rc); return rc; @@ -5160,9 +5295,7 @@ static int smbchg_unprepare_for_pulsing(struct smbchg_chip *chip) /* enable HVDCP */ pr_smb(PR_MISC, "Enable HVDCP\n"); - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, HVDCP_EN_BIT); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, false, 1); if (rc < 0) { pr_err("Couldn't enable HVDCP rc=%d\n", rc); return rc; @@ -5203,6 +5336,15 @@ static int smbchg_unprepare_for_pulsing(struct smbchg_chip *chip) */ chip->parallel.enabled_once = false; + /* Enable AICL */ + pr_smb(PR_MISC, "Enable AICL\n"); + rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USB_AICL_CFG, + AICL_EN_BIT, AICL_EN_BIT); + if (rc < 0) { + pr_err("Couldn't enable AICL rc=%d\n", rc); + goto out; + } + /* fake an insertion */ pr_smb(PR_MISC, "Faking Insertion\n"); rc = fake_insertion_removal(chip, true); @@ -5212,15 +5354,6 @@ static int smbchg_unprepare_for_pulsing(struct smbchg_chip *chip) } chip->hvdcp_3_det_ignore_uv = false; - /* Enable AICL */ - pr_smb(PR_MISC, "Enable AICL\n"); - rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USB_AICL_CFG, - AICL_EN_BIT, 0); - if (rc < 0) { - pr_err("Couldn't enable AICL rc=%d\n", rc); - return rc; - } - out: /* * There are many QC 2.0 chargers that collapse before the aicl deglitch @@ -5243,6 +5376,9 @@ out: pr_smb(PR_MISC, "HVDCP removed\n"); update_usb_status(chip, 0, 0); } + + smbchg_handle_hvdcp3_disable(chip); + return rc; } @@ -5250,49 +5386,63 @@ out: #define APSD_RERUN BIT(0) static int rerun_apsd(struct smbchg_chip *chip) { - int rc; + int rc = 0; - reinit_completion(&chip->src_det_raised); - reinit_completion(&chip->usbin_uv_lowered); - reinit_completion(&chip->src_det_lowered); - reinit_completion(&chip->usbin_uv_raised); + chip->hvdcp_3_det_ignore_uv = true; - /* re-run APSD */ - rc = smbchg_masked_write(chip, chip->usb_chgpth_base + USB_CMD_APSD, - APSD_RERUN, APSD_RERUN); - if (rc) { - pr_err("Couldn't re-run APSD rc=%d\n", rc); - return rc; - } + if (chip->schg_version == QPNP_SCHG_LITE) { + pr_smb(PR_STATUS, "Re-running APSD\n"); + reinit_completion(&chip->src_det_raised); + reinit_completion(&chip->usbin_uv_lowered); + reinit_completion(&chip->src_det_lowered); + reinit_completion(&chip->usbin_uv_raised); - pr_smb(PR_MISC, "Waiting on rising usbin uv\n"); - rc = wait_for_usbin_uv(chip, true); - if (rc < 0) { - pr_err("wait for usbin uv failed rc = %d\n", rc); - return rc; - } + /* re-run APSD */ + rc = smbchg_masked_write(chip, + chip->usb_chgpth_base + USB_CMD_APSD, + APSD_RERUN, APSD_RERUN); + if (rc) { + pr_err("Couldn't re-run APSD rc=%d\n", rc); + goto out; + } - pr_smb(PR_MISC, "Waiting on falling src det\n"); - rc = wait_for_src_detect(chip, false); - if (rc < 0) { - pr_err("wait for src detect failed rc = %d\n", rc); - return rc; - } + pr_smb(PR_MISC, "Waiting on rising usbin uv\n"); + rc = wait_for_usbin_uv(chip, true); + if (rc < 0) { + pr_err("wait for usbin uv failed rc = %d\n", rc); + goto out; + } - pr_smb(PR_MISC, "Waiting on falling usbin uv\n"); - rc = wait_for_usbin_uv(chip, false); - if (rc < 0) { - pr_err("wait for usbin uv failed rc = %d\n", rc); - return rc; - } + pr_smb(PR_MISC, "Waiting on falling src det\n"); + rc = wait_for_src_detect(chip, false); + if (rc < 0) { + pr_err("wait for src detect failed rc = %d\n", rc); + goto out; + } - pr_smb(PR_MISC, "Waiting on rising src det\n"); - rc = wait_for_src_detect(chip, true); - if (rc < 0) { - pr_err("wait for src detect failed rc = %d\n", rc); - return rc; + pr_smb(PR_MISC, "Waiting on falling usbin uv\n"); + rc = wait_for_usbin_uv(chip, false); + if (rc < 0) { + pr_err("wait for usbin uv failed rc = %d\n", rc); + goto out; + } + + pr_smb(PR_MISC, "Waiting on rising src det\n"); + rc = wait_for_src_detect(chip, true); + if (rc < 0) { + pr_err("wait for src detect failed rc = %d\n", rc); + goto out; + } + } else { + pr_smb(PR_STATUS, "Faking Removal\n"); + rc = fake_insertion_removal(chip, false); + msleep(500); + pr_smb(PR_STATUS, "Faking Insertion\n"); + rc = fake_insertion_removal(chip, true); } +out: + chip->hvdcp_3_det_ignore_uv = false; return rc; } @@ -5332,6 +5482,12 @@ static int smbchg_prepare_for_pulsing_lite(struct smbchg_chip *chip) { int rc = 0; + pr_smb(PR_MISC, "HVDCP voting for 300mA ICL\n"); + rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, true, 300); + if (rc < 0) { + pr_err("Couldn't vote for 300mA HVDCP ICL rc=%d\n", rc); + return rc; + } /* check if HVDCP is already in 5V continuous mode */ if (is_hvdcp_5v_cont_mode(chip)) { pr_smb(PR_MISC, "HVDCP by default is in 5V continuous mode\n"); @@ -5358,19 +5514,10 @@ static int smbchg_prepare_for_pulsing_lite(struct smbchg_chip *chip) goto out; } - pr_smb(PR_MISC, "HVDCP voting for 300mA ICL\n"); - rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, true, 300); - if (rc < 0) { - pr_err("Couldn't vote for 300mA HVDCP ICL rc=%d\n", rc); - goto out; - } - pr_smb(PR_MISC, "Disable AICL\n"); smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USB_AICL_CFG, AICL_EN_BIT, 0); - chip->hvdcp_3_det_ignore_uv = true; - /* re-run APSD */ rc = rerun_apsd(chip); if (rc) { @@ -5378,8 +5525,6 @@ static int smbchg_prepare_for_pulsing_lite(struct smbchg_chip *chip) goto out; } - chip->hvdcp_3_det_ignore_uv = false; - pr_smb(PR_MISC, "Enable AICL\n"); smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USB_AICL_CFG, AICL_EN_BIT, AICL_EN_BIT); @@ -5408,6 +5553,10 @@ static int smbchg_prepare_for_pulsing_lite(struct smbchg_chip *chip) out: chip->hvdcp_3_det_ignore_uv = false; restore_from_hvdcp_detection(chip); + if (!is_src_detect_high(chip)) { + pr_smb(PR_MISC, "HVDCP removed - force removal\n"); + update_usb_status(chip, 0, true); + } return rc; } @@ -5427,6 +5576,12 @@ static int smbchg_unprepare_for_pulsing_lite(struct smbchg_chip *chip) if (rc < 0) pr_err("Couldn't retract HVDCP ICL vote rc=%d\n", rc); + if (!is_src_detect_high(chip)) { + pr_smb(PR_MISC, "HVDCP removed\n"); + update_usb_status(chip, 0, 0); + } + smbchg_handle_hvdcp3_disable(chip); + return rc; } @@ -5564,6 +5719,7 @@ static void update_typec_otg_status(struct smbchg_chip *chip, int mode, bool force) { union power_supply_propval pval = {0, }; + pr_smb(PR_TYPEC, "typec mode = %d\n", mode); if (mode == POWER_SUPPLY_TYPE_DFP) { @@ -5585,6 +5741,21 @@ static void update_typec_otg_status(struct smbchg_chip *chip, int mode, } } +static int smbchg_set_sdp_current(struct smbchg_chip *chip, int current_ma) +{ + if (chip->usb_supply_type == POWER_SUPPLY_TYPE_USB) { + /* Override if type-c charger used */ + if (chip->typec_current_ma > 500 && + current_ma < chip->typec_current_ma) { + current_ma = chip->typec_current_ma; + } + pr_smb(PR_MISC, "from USB current_ma = %d\n", current_ma); + vote(chip->usb_icl_votable, PSY_ICL_VOTER, true, current_ma); + } + + return 0; +} + static int smbchg_usb_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -5593,7 +5764,12 @@ static int smbchg_usb_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CURRENT_MAX: - val->intval = chip->usb_current_max; + case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + if (chip->usb_icl_votable) + val->intval = get_client_vote(chip->usb_icl_votable, + PSY_ICL_VOTER) * 1000; + else + val->intval = 0; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = chip->usb_present; @@ -5602,6 +5778,9 @@ static int smbchg_usb_get_property(struct power_supply *psy, val->intval = chip->usb_online; break; case POWER_SUPPLY_PROP_TYPE: + val->intval = chip->usb_psy_d.type; + break; + case POWER_SUPPLY_PROP_REAL_TYPE: val->intval = chip->usb_supply_type; break; case POWER_SUPPLY_PROP_HEALTH: @@ -5620,25 +5799,26 @@ static int smbchg_usb_set_property(struct power_supply *psy, struct smbchg_chip *chip = power_supply_get_drvdata(psy); switch (psp) { - case POWER_SUPPLY_PROP_CURRENT_MAX: - chip->usb_current_max = val->intval; - break; case POWER_SUPPLY_PROP_ONLINE: chip->usb_online = val->intval; break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + smbchg_set_sdp_current(chip, val->intval / 1000); default: return -EINVAL; } - power_supply_changed(psy); return 0; } static int -smbchg_usb_is_writeable(struct power_supply *psy, enum power_supply_property psp) +smbchg_usb_is_writeable(struct power_supply *psy, + enum power_supply_property psp) { switch (psp) { case POWER_SUPPLY_PROP_CURRENT_MAX: + case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: return 1; default: break; @@ -5658,7 +5838,9 @@ static enum power_supply_property smbchg_usb_properties[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_REAL_TYPE, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_SDP_CURRENT_MAX, }; #define CHARGE_OUTPUT_VTG_RATIO 840 @@ -5703,6 +5885,8 @@ static enum power_supply_property smbchg_battery_properties[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_RESISTANCE_ID, + POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE, POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, @@ -5713,6 +5897,8 @@ static enum power_supply_property smbchg_battery_properties[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_RERUN_AICL, POWER_SUPPLY_PROP_RESTRICTED_CHARGING, + POWER_SUPPLY_PROP_ALLOW_HVDCP3, + POWER_SUPPLY_PROP_MAX_PULSE_ALLOWED, }; static int smbchg_battery_set_property(struct power_supply *psy, @@ -5760,7 +5946,7 @@ static int smbchg_battery_set_property(struct power_supply *psy, * Trigger a panic if there is an error while switching * buck frequency. This will prevent LS FET damage. */ - BUG_ON(1); + WARN_ON(1); } rc = smbchg_otg_pulse_skip_disable(chip, @@ -5790,6 +5976,12 @@ static int smbchg_battery_set_property(struct power_supply *psy, if (chip->typec_psy) update_typec_otg_status(chip, val->intval, false); break; + case POWER_SUPPLY_PROP_ALLOW_HVDCP3: + if (chip->allow_hvdcp3_detection != val->intval) { + chip->allow_hvdcp3_detection = !!val->intval; + power_supply_changed(chip->batt_psy); + } + break; default: return -EINVAL; } @@ -5813,6 +6005,7 @@ static int smbchg_battery_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_DP_DM: case POWER_SUPPLY_PROP_RERUN_AICL: case POWER_SUPPLY_PROP_RESTRICTED_CHARGING: + case POWER_SUPPLY_PROP_ALLOW_HVDCP3: rc = 1; break; default: @@ -5886,6 +6079,12 @@ static int smbchg_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = get_prop_batt_voltage_now(chip); break; + case POWER_SUPPLY_PROP_RESISTANCE_ID: + val->intval = get_prop_batt_resistance_id(chip); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + val->intval = get_prop_batt_full_charge(chip); + break; case POWER_SUPPLY_PROP_TEMP: val->intval = get_prop_batt_temp(chip); break; @@ -5913,6 +6112,12 @@ static int smbchg_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW: val->intval = smbchg_get_iusb(chip); break; + case POWER_SUPPLY_PROP_ALLOW_HVDCP3: + val->intval = chip->allow_hvdcp3_detection; + break; + case POWER_SUPPLY_PROP_MAX_PULSE_ALLOWED: + val->intval = chip->max_pulse_allowed; + break; default: return -EINVAL; } @@ -6134,7 +6339,10 @@ static irqreturn_t fastchg_handler(int irq, void *_chip) struct smbchg_chip *chip = _chip; pr_smb(PR_INTERRUPT, "p2f triggered\n"); - smbchg_parallel_usb_check_ok(chip); + if (is_usb_present(chip) || is_dc_present(chip)) { + smbchg_detect_parallel_charger(chip); + smbchg_parallel_usb_check_ok(chip); + } if (chip->batt_psy) power_supply_changed(chip->batt_psy); smbchg_charging_status_change(chip); @@ -6323,8 +6531,7 @@ static irqreturn_t usbin_uv_handler(int irq, void *_chip) */ if (!(reg & USBIN_UV_BIT) && !(reg & USBIN_SRC_DET_BIT)) { pr_smb(PR_MISC, "setting usb dp=f dm=f\n"); - if (chip->dpdm_reg && !regulator_is_enabled(chip->dpdm_reg)) - rc = regulator_enable(chip->dpdm_reg); + rc = smbchg_request_dpdm(chip, true); if (rc < 0) { pr_err("Couldn't enable DP/DM for pulsing rc=%d\n", rc); return rc; @@ -6568,20 +6775,13 @@ static int determine_initial_status(struct smbchg_chip *chip) } else { usbid_change_handler(0, chip); } - src_detect_handler(0, chip); chip->usb_present = is_usb_present(chip); chip->dc_present = is_dc_present(chip); if (chip->usb_present) { - int rc = 0; pr_smb(PR_MISC, "setting usb dp=f dm=f\n"); - if (chip->dpdm_reg && !regulator_is_enabled(chip->dpdm_reg)) - rc = regulator_enable(chip->dpdm_reg); - if (rc < 0) { - pr_err("Couldn't enable DP/DM for pulsing rc=%d\n", rc); - return rc; - } + smbchg_request_dpdm(chip, true); handle_usb_insertion(chip); } else { handle_usb_removal(chip); @@ -6621,6 +6821,7 @@ static const char * const bpd_label[] = { static inline int get_bpd(const char *name) { int i = 0; + for (i = 0; i < ARRAY_SIZE(bpd_label); i++) { if (strcmp(bpd_label[i], name) == 0) return i; @@ -6746,7 +6947,22 @@ static int smbchg_hw_init(struct smbchg_chip *chip) chip->revision[ANA_MAJOR], chip->revision[ANA_MINOR]); /* Setup 9V HVDCP */ - if (!chip->hvdcp_not_supported) { + if (chip->hvdcp_not_supported) { + rc = vote(chip->hvdcp_enable_votable, HVDCP_PMIC_VOTER, + true, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't disable HVDCP rc=%d\n", + rc); + return rc; + } + } else { + rc = vote(chip->hvdcp_enable_votable, HVDCP_PMIC_VOTER, + true, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't enable HVDCP rc=%d\n", + rc); + return rc; + } rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_9V); @@ -6898,9 +7114,9 @@ static int smbchg_hw_init(struct smbchg_chip *chip) if (chip->iterm_disabled) { dev_err(chip->dev, "Error: Both iterm_disabled and iterm_ma set\n"); return -EINVAL; - } else { - smbchg_iterm_set(chip, chip->iterm_ma); } + + smbchg_iterm_set(chip, chip->iterm_ma); } /* set the safety time voltage */ @@ -7140,7 +7356,7 @@ static int smbchg_hw_init(struct smbchg_chip *chip) return rc; } -static struct of_device_id smbchg_match_table[] = { +static const struct of_device_id smbchg_match_table[] = { { .compatible = "qcom,qpnp-smbcharger", }, @@ -7157,7 +7373,7 @@ do { \ prop = -EINVAL; \ \ retval = of_property_read_u32(chip->pdev->dev.of_node, \ - "qcom," dt_property , \ + "qcom," dt_property, \ &prop); \ \ if ((retval == -EINVAL) && optional) \ @@ -7196,10 +7412,9 @@ static int smb_parse_wipower_map_dt(struct smbchg_chip *chip, num = total_elements / RANGE_ENTRY; map->entries = devm_kzalloc(chip->dev, num * sizeof(struct ilim_entry), GFP_KERNEL); - if (!map->entries) { - dev_err(chip->dev, "kzalloc failed for default ilim\n"); + if (!map->entries) return -ENOMEM; - } + for (i = 0; i < num; i++) { map->entries[i].vmin_uv = be32_to_cpup(data++); map->entries[i].vmax_uv = be32_to_cpup(data++); @@ -7264,6 +7479,7 @@ err: #define DEFAULT_VLED_MAX_UV 3500000 #define DEFAULT_FCC_MA 2000 +#define DEFAULT_NUM_OF_PULSE_ALLOWED 20 static int smb_parse_dt(struct smbchg_chip *chip) { int rc = 0, ocp_thresh = -EINVAL; @@ -7322,6 +7538,11 @@ static int smb_parse_dt(struct smbchg_chip *chip) if (chip->parallel.min_current_thr_ma != -EINVAL && chip->parallel.min_9v_current_thr_ma != -EINVAL) chip->parallel.avail = true; + + OF_PROP_READ(chip, chip->max_pulse_allowed, + "max-pulse-allowed", rc, 1); + if (chip->max_pulse_allowed == -EINVAL) + chip->max_pulse_allowed = DEFAULT_NUM_OF_PULSE_ALLOWED; /* * use the dt values if they exist, otherwise do not touch the params */ @@ -7472,19 +7693,19 @@ static int smb_parse_dt(struct smbchg_chip *chip) #define SMBCHG_LITE_MISC_SUBTYPE 0x57 static int smbchg_request_irq(struct smbchg_chip *chip, struct device_node *child, - int irq_num, char *irq_name, + int *irq_num, char *irq_name, irqreturn_t (irq_handler)(int irq, void *_chip), int flags) { int rc; - irq_num = of_irq_get_byname(child, irq_name); - if (irq_num < 0) { + *irq_num = of_irq_get_byname(child, irq_name); + if (*irq_num < 0) { dev_err(chip->dev, "Unable to get %s irqn", irq_name); rc = -ENXIO; } rc = devm_request_threaded_irq(chip->dev, - irq_num, NULL, irq_handler, flags, irq_name, + *irq_num, NULL, irq_handler, flags, irq_name, chip); if (rc < 0) { dev_err(chip->dev, "Unable to request %s irq: %dn", @@ -7526,26 +7747,28 @@ static int smbchg_request_irqs(struct smbchg_chip *chip) case SMBCHG_CHGR_SUBTYPE: case SMBCHG_LITE_CHGR_SUBTYPE: rc = smbchg_request_irq(chip, child, - chip->chg_error_irq, "chg-error", + &chip->chg_error_irq, "chg-error", chg_error_handler, flags); if (rc < 0) return rc; - rc = smbchg_request_irq(chip, child, chip->taper_irq, + rc = smbchg_request_irq(chip, child, &chip->taper_irq, "chg-taper-thr", taper_handler, (IRQF_TRIGGER_RISING | IRQF_ONESHOT)); if (rc < 0) return rc; disable_irq_nosync(chip->taper_irq); - rc = smbchg_request_irq(chip, child, chip->chg_term_irq, + rc = smbchg_request_irq(chip, child, + &chip->chg_term_irq, "chg-tcc-thr", chg_term_handler, (IRQF_TRIGGER_RISING | IRQF_ONESHOT)); if (rc < 0) return rc; - rc = smbchg_request_irq(chip, child, chip->recharge_irq, + rc = smbchg_request_irq(chip, child, + &chip->recharge_irq, "chg-rechg-thr", recharge_handler, flags); if (rc < 0) return rc; - rc = smbchg_request_irq(chip, child, chip->fastchg_irq, + rc = smbchg_request_irq(chip, child, &chip->fastchg_irq, "chg-p2f-thr", fastchg_handler, flags); if (rc < 0) return rc; @@ -7555,36 +7778,37 @@ static int smbchg_request_irqs(struct smbchg_chip *chip) break; case SMBCHG_BAT_IF_SUBTYPE: case SMBCHG_LITE_BAT_IF_SUBTYPE: - rc = smbchg_request_irq(chip, child, chip->batt_hot_irq, + rc = smbchg_request_irq(chip, child, + &chip->batt_hot_irq, "batt-hot", batt_hot_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->batt_warm_irq, + &chip->batt_warm_irq, "batt-warm", batt_warm_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->batt_cool_irq, + &chip->batt_cool_irq, "batt-cool", batt_cool_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->batt_cold_irq, + &chip->batt_cold_irq, "batt-cold", batt_cold_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->batt_missing_irq, + &chip->batt_missing_irq, "batt-missing", batt_pres_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->vbat_low_irq, + &chip->vbat_low_irq, "batt-low", vbat_low_handler, flags); if (rc < 0) return rc; - + enable_irq_wake(chip->batt_hot_irq); enable_irq_wake(chip->batt_warm_irq); enable_irq_wake(chip->batt_cool_irq); @@ -7595,24 +7819,24 @@ static int smbchg_request_irqs(struct smbchg_chip *chip) case SMBCHG_USB_CHGPTH_SUBTYPE: case SMBCHG_LITE_USB_CHGPTH_SUBTYPE: rc = smbchg_request_irq(chip, child, - chip->usbin_uv_irq, + &chip->usbin_uv_irq, "usbin-uv", usbin_uv_handler, flags | IRQF_EARLY_RESUME); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->usbin_ov_irq, + &chip->usbin_ov_irq, "usbin-ov", usbin_ov_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->src_detect_irq, + &chip->src_detect_irq, "usbin-src-det", src_detect_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->aicl_done_irq, + &chip->aicl_done_irq, "aicl-done", aicl_done_handler, (IRQF_TRIGGER_RISING | IRQF_ONESHOT)); @@ -7621,18 +7845,18 @@ static int smbchg_request_irqs(struct smbchg_chip *chip) if (chip->schg_version != QPNP_SCHG_LITE) { rc = smbchg_request_irq(chip, child, - chip->otg_fail_irq, "otg-fail", + &chip->otg_fail_irq, "otg-fail", otg_fail_handler, flags); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->otg_oc_irq, "otg-oc", + &chip->otg_oc_irq, "otg-oc", otg_oc_handler, (IRQF_TRIGGER_RISING | IRQF_ONESHOT)); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->usbid_change_irq, "usbid-change", + &chip->usbid_change_irq, "usbid-change", usbid_change_handler, (IRQF_TRIGGER_FALLING | IRQF_ONESHOT)); if (rc < 0) @@ -7651,7 +7875,7 @@ static int smbchg_request_irqs(struct smbchg_chip *chip) break; case SMBCHG_DC_CHGPTH_SUBTYPE: case SMBCHG_LITE_DC_CHGPTH_SUBTYPE: - rc = smbchg_request_irq(chip, child, chip->dcin_uv_irq, + rc = smbchg_request_irq(chip, child, &chip->dcin_uv_irq, "dcin-uv", dcin_uv_handler, flags); if (rc < 0) return rc; @@ -7659,16 +7883,17 @@ static int smbchg_request_irqs(struct smbchg_chip *chip) break; case SMBCHG_MISC_SUBTYPE: case SMBCHG_LITE_MISC_SUBTYPE: - rc = smbchg_request_irq(chip, child, chip->power_ok_irq, + rc = smbchg_request_irq(chip, child, + &chip->power_ok_irq, "power-ok", power_ok_handler, flags); if (rc < 0) return rc; - rc = smbchg_request_irq(chip, child, chip->chg_hot_irq, + rc = smbchg_request_irq(chip, child, &chip->chg_hot_irq, "temp-shutdown", chg_hot_handler, flags); if (rc < 0) return rc; - rc = smbchg_request_irq(chip, child, chip->wdog_timeout_irq, - "wdog-timeout", + rc = smbchg_request_irq(chip, child, + &chip->wdog_timeout_irq, "wdog-timeout", wdog_timeout_handler, flags); if (rc < 0) return rc; @@ -7679,19 +7904,19 @@ static int smbchg_request_irqs(struct smbchg_chip *chip) break; case SMBCHG_LITE_OTG_SUBTYPE: rc = smbchg_request_irq(chip, child, - chip->usbid_change_irq, "usbid-change", + &chip->usbid_change_irq, "usbid-change", usbid_change_handler, (IRQF_TRIGGER_FALLING | IRQF_ONESHOT)); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->otg_oc_irq, "otg-oc", + &chip->otg_oc_irq, "otg-oc", otg_oc_handler, (IRQF_TRIGGER_RISING | IRQF_ONESHOT)); if (rc < 0) return rc; rc = smbchg_request_irq(chip, child, - chip->otg_fail_irq, "otg-fail", + &chip->otg_fail_irq, "otg-fail", otg_fail_handler, flags); if (rc < 0) return rc; @@ -7828,8 +8053,7 @@ static int create_debugfs_entries(struct smbchg_chip *chip) } ent = debugfs_create_file("force_dcin_icl_check", - S_IFREG | S_IWUSR | S_IRUGO, - chip->debug_root, chip, + 00100644, chip->debug_root, chip, &force_dcin_icl_ops); if (!ent) { dev_err(chip->dev, @@ -7870,6 +8094,7 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) chip->schg_version = QPNP_SCHG; break; case PMI8950: + chip->wa_flags |= SMBCHG_RESTART_WA; case PMI8937: chip->wa_flags |= SMBCHG_BATT_OV_WA; if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ { @@ -7927,20 +8152,18 @@ static void rerun_hvdcp_det_if_necessary(struct smbchg_chip *chip) pr_err("Couldn't vote for 300mA for suspend wa, going ahead rc=%d\n", rc); - pr_smb(PR_STATUS, "Faking Removal\n"); - fake_insertion_removal(chip, false); - msleep(500); - pr_smb(PR_STATUS, "Faking Insertion\n"); - fake_insertion_removal(chip, true); + rc = rerun_apsd(chip); + if (rc) + pr_err("APSD rerun failed rc=%d\n", rc); read_usb_type(chip, &usb_type_name, &usb_supply_type); if (usb_supply_type != POWER_SUPPLY_TYPE_USB_DCP) { msleep(500); - pr_smb(PR_STATUS, "Fake Removal again as type!=DCP\n"); - fake_insertion_removal(chip, false); - msleep(500); - pr_smb(PR_STATUS, "Fake Insert again as type!=DCP\n"); - fake_insertion_removal(chip, true); + pr_smb(PR_STATUS, "Rerun APSD as type !=DCP\n"); + + rc = rerun_apsd(chip); + if (rc) + pr_err("APSD rerun failed rc=%d\n", rc); } rc = vote(chip->usb_icl_votable, @@ -7948,6 +8171,14 @@ static void rerun_hvdcp_det_if_necessary(struct smbchg_chip *chip) if (rc < 0) pr_err("Couldn't vote for 0 for suspend wa, going ahead rc=%d\n", rc); + + /* Schedule work for HVDCP detection */ + if (!chip->hvdcp_not_supported) { + cancel_delayed_work_sync(&chip->hvdcp_det_work); + smbchg_stay_awake(chip, PM_DETECT_HVDCP); + schedule_delayed_work(&chip->hvdcp_det_work, + msecs_to_jiffies(HVDCP_NOTIFY_MS)); + } } } @@ -7956,7 +8187,7 @@ static int smbchg_probe(struct platform_device *pdev) int rc; struct smbchg_chip *chip; struct power_supply *typec_psy = NULL; - struct qpnp_vadc_chip *vadc_dev, *vchg_vadc_dev; + struct qpnp_vadc_chip *vadc_dev = NULL, *vchg_vadc_dev = NULL; const char *typec_psy_name; struct power_supply_config usb_psy_cfg = {}; struct power_supply_config batt_psy_cfg = {}; @@ -8090,6 +8321,15 @@ static int smbchg_probe(struct platform_device *pdev) goto votables_cleanup; } + chip->hvdcp_enable_votable = create_votable( + "HVDCP_ENABLE", + VOTE_MIN, + smbchg_hvdcp_enable_cb, chip); + if (IS_ERR(chip->hvdcp_enable_votable)) { + rc = PTR_ERR(chip->hvdcp_enable_votable); + goto votables_cleanup; + } + INIT_WORK(&chip->usb_set_online_work, smbchg_usb_update_online_work); INIT_DELAYED_WORK(&chip->parallel_en_work, smbchg_parallel_usb_en_work); @@ -8178,18 +8418,10 @@ static int smbchg_probe(struct platform_device *pdev) goto votables_cleanup; } - if (of_find_property(chip->dev->of_node, "dpdm-supply", NULL)) { - chip->dpdm_reg = devm_regulator_get(chip->dev, "dpdm"); - if (IS_ERR(chip->dpdm_reg)) { - rc = PTR_ERR(chip->dpdm_reg); - goto votables_cleanup; - } - } - rc = smbchg_hw_init(chip); if (rc < 0) { dev_err(&pdev->dev, - "Unable to intialize hardware rc = %d\n", rc); + "Unable to initialize hardware rc = %d\n", rc); goto out; } @@ -8247,6 +8479,7 @@ static int smbchg_probe(struct platform_device *pdev) goto out; } } + chip->allow_hvdcp3_detection = true; if (chip->cfg_chg_led_support && chip->schg_version == QPNP_SCHG_LITE) { @@ -8275,6 +8508,7 @@ static int smbchg_probe(struct platform_device *pdev) rerun_hvdcp_det_if_necessary(chip); + update_usb_status(chip, is_usb_present(chip), false); dump_regs(chip); create_debugfs_entries(chip); dev_info(chip->dev, @@ -8292,6 +8526,8 @@ unregister_led_class: out: handle_usb_removal(chip); votables_cleanup: + if (chip->hvdcp_enable_votable) + destroy_votable(chip->hvdcp_enable_votable); if (chip->aicl_deglitch_short_votable) destroy_votable(chip->aicl_deglitch_short_votable); if (chip->hw_aicl_rerun_enable_indirect_votable) @@ -8343,6 +8579,12 @@ static void smbchg_shutdown(struct platform_device *pdev) if (!is_hvdcp_present(chip)) return; + pr_smb(PR_MISC, "Reducing to 500mA\n"); + rc = vote(chip->usb_icl_votable, SHUTDOWN_WORKAROUND_ICL_VOTER, true, + 500); + if (rc < 0) + pr_err("Couldn't vote 500mA ICL\n"); + pr_smb(PR_MISC, "Disable Parallel\n"); mutex_lock(&chip->parallel.lock); smbchg_parallel_en = 0; @@ -8365,11 +8607,9 @@ static void smbchg_shutdown(struct platform_device *pdev) disable_irq(chip->otg_oc_irq); disable_irq(chip->power_ok_irq); disable_irq(chip->recharge_irq); - disable_irq(chip->src_detect_irq); disable_irq(chip->taper_irq); disable_irq(chip->usbid_change_irq); disable_irq(chip->usbin_ov_irq); - disable_irq(chip->usbin_uv_irq); disable_irq(chip->vbat_low_irq); disable_irq(chip->wdog_timeout_irq); @@ -8412,8 +8652,7 @@ static void smbchg_shutdown(struct platform_device *pdev) /* disable HVDCP */ pr_smb(PR_MISC, "Disable HVDCP\n"); - rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, 0); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PMIC_VOTER, true, 0); if (rc < 0) pr_err("Couldn't disable HVDCP rc=%d\n", rc); @@ -8430,6 +8669,9 @@ static void smbchg_shutdown(struct platform_device *pdev) if (rc < 0) pr_err("Couldn't fake insertion rc=%d\n", rc); + disable_irq(chip->src_detect_irq); + disable_irq(chip->usbin_uv_irq); + pr_smb(PR_MISC, "Wait 1S to settle\n"); msleep(1000); chip->hvdcp_3_det_ignore_uv = false; |
