Loading drivers/power/supply/qcom/qpnp-smb5.c +44 −41 Original line number Diff line number Diff line Loading @@ -177,6 +177,11 @@ module_param_named( debug_mask, __debug_mask, int, 0600 ); static int __pd_disabled; module_param_named( pd_disabled, __pd_disabled, int, 0600 ); static int __weak_chg_icl_ua = 500000; module_param_named( weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600 Loading Loading @@ -434,7 +439,6 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_MODE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, Loading Loading @@ -515,9 +519,6 @@ static int smb5_usb_get_prop(struct power_supply *psy, else rc = smblib_get_prop_typec_cc_orientation(chg, val); break; case POWER_SUPPLY_PROP_PD_ALLOWED: rc = smblib_get_prop_pd_allowed(chg, val); break; case POWER_SUPPLY_PROP_PD_ACTIVE: val->intval = chg->pd_active; break; Loading Loading @@ -605,12 +606,6 @@ static int smb5_usb_set_prop(struct power_supply *psy, struct smb_charger *chg = &chip->chg; int rc = 0; mutex_lock(&chg->lock); if (!chg->typec_present) { rc = -EINVAL; goto unlock; } switch (psp) { case POWER_SUPPLY_PROP_PD_CURRENT_MAX: rc = smblib_set_prop_pd_current_max(chg, val); Loading Loading @@ -652,8 +647,6 @@ static int smb5_usb_set_prop(struct power_supply *psy, break; } unlock: mutex_unlock(&chg->lock); return rc; } Loading Loading @@ -1425,6 +1418,15 @@ static int smb5_configure_typec(struct smb_charger *chg) { int rc; /* disable apsd */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return rc; } rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG, TYPEC_CCOUT_DETACH_INT_EN_BIT | TYPEC_CCOUT_ATTACH_INT_EN_BIT); Loading Loading @@ -1459,14 +1461,6 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) { int rc; /* configure micro USB mode */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc); return rc; } rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, MICRO_USB_STATE_CHANGE_INT_EN_BIT, MICRO_USB_STATE_CHANGE_INT_EN_BIT); Loading Loading @@ -1500,7 +1494,6 @@ static int smb5_init_hw(struct smb5 *chip) &chg->default_icl_ua); /* Use SW based VBUS control, disable HW autonomous mode */ /* TODO: auth can be enabled through vote based on APSD flow */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, HVDCP_AUTH_ALG_EN_CFG_BIT); Loading Loading @@ -1537,10 +1530,22 @@ static int smb5_init_hw(struct smb5 *chip) type = !!(val & EN_MICRO_USB_MODE_BIT); } chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB : POWER_SUPPLY_CONNECTOR_TYPEC; pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC"); if (type) { chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; smblib_rerun_apsd_if_required(chg); rc = smb5_configure_micro_usb(chg); } else { chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC; rc = smb5_configure_typec(chg); } if (rc < 0) { dev_err(chg->dev, "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc); return rc; } /* * PMI632 based hw init: * - Initialize flash module for PMI632 Loading @@ -1548,8 +1553,6 @@ static int smb5_init_hw(struct smb5 *chip) if (chg->smb_version == PMI632_SUBTYPE) schgm_flash_init(chg); smblib_rerun_apsd_if_required(chg); /* vote 0mA on usb_icl for non battery platforms */ vote(chg->usb_icl_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); Loading @@ -1565,12 +1568,6 @@ static int smb5_init_hw(struct smb5 *chip) vote(chg->fv_votable, BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0, chg->batt_profile_fv_uv); vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER, chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0); /* Some h/w limit maximum supported ICL */ vote(chg->usb_icl_votable, HW_LIMIT_VOTER, Loading @@ -1594,16 +1591,6 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) rc = smb5_configure_micro_usb(chg); else rc = smb5_configure_typec(chg); if (rc < 0) { dev_err(chg->dev, "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc); return rc; } /* configure VBUS for software control */ rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0); if (rc < 0) { Loading Loading @@ -1812,11 +1799,21 @@ static int smb5_determine_initial_status(struct smb5 *chip) { struct smb_irq_data irq_data = {chip, "determine-initial-status"}; struct smb_charger *chg = &chip->chg; union power_supply_propval val; int rc; rc = smblib_get_prop_usb_present(chg, &val); if (rc < 0) { pr_err("Couldn't get usb present rc=%d\n", rc); return rc; } chg->early_usb_attach = val.intval; if (chg->bms_psy) smblib_suspend_on_debug_battery(chg); usb_plugin_irq_handler(0, &irq_data); typec_attach_detach_irq_handler(0, &irq_data); typec_state_change_irq_handler(0, &irq_data); usb_source_change_irq_handler(0, &irq_data); chg_state_change_irq_handler(0, &irq_data); Loading Loading @@ -2008,6 +2005,7 @@ static struct smb_irq_info smb5_irqs[] = { }, [TYPEC_ATTACH_DETACH_IRQ] = { .name = "typec-attach-detach", .handler = typec_attach_detach_irq_handler, }, [TYPEC_LEGACY_CABLE_DETECT_IRQ] = { .name = "typec-legacy-cable-detect", Loading Loading @@ -2303,6 +2301,7 @@ static int smb5_probe(struct platform_device *pdev) chg = &chip->chg; chg->dev = &pdev->dev; chg->debug_mask = &__debug_mask; chg->pd_disabled = &__pd_disabled; chg->weak_chg_icl_ua = &__weak_chg_icl_ua; chg->mode = PARALLEL_MASTER; chg->irq_info = smb5_irqs; Loading Loading @@ -2452,6 +2451,10 @@ static int smb5_remove(struct platform_device *pdev) struct smb5 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; /* force enable APSD */ smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT); smb5_free_interrupts(chg); smblib_deinit(chg); platform_set_drvdata(pdev, NULL); Loading drivers/power/supply/qcom/smb5-lib.c +149 −248 Original line number Diff line number Diff line Loading @@ -663,10 +663,6 @@ static void smblib_uusb_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc); if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; if (data) { Loading Loading @@ -954,18 +950,6 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, (bool)suspend); } static int smblib_pd_disallowed_votable_indirect_callback( struct votable *votable, void *data, int disallowed, const char *client) { struct smb_charger *chg = data; int rc; rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER, !disallowed, 0); return rc; } static int smblib_awake_vote_callback(struct votable *votable, void *data, int awake, const char *client) { Loading Loading @@ -1989,13 +1973,6 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, return rc; } int smblib_get_prop_pd_allowed(struct smb_charger *chg, union power_supply_propval *val) { val->intval = get_effective_result(chg->pd_allowed_votable); return 0; } int smblib_get_prop_input_current_settled(struct smb_charger *chg, union power_supply_propval *val) { Loading Loading @@ -2039,13 +2016,7 @@ int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg, int smblib_get_pe_start(struct smb_charger *chg, union power_supply_propval *val) { /* * hvdcp timeout voter is the last one to allow pd. Use its vote * to indicate start of pe engine */ val->intval = !get_client_vote_locked(chg->pd_disallowed_votable_indirect, APSD_VOTER); val->intval = chg->ok_to_pd; return 0; } Loading Loading @@ -2298,14 +2269,14 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg, return rc; } static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val) { int rc = 0; chg->pd_active = pd_active; chg->pd_active = val->intval; if (chg->pd_active) { vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); /* Loading @@ -2313,24 +2284,24 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) * It is guaranteed that pd_active is set prior to * pd_current_max */ rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); if (rc < 0) smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n", rc); /* clear USB ICL vote for DCP_VOTER */ rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); if (rc < 0) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); /* remove USB_PSY_VOTER */ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); if (rc < 0) smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc); vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); } else { vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); /* PD hard resets failed, rerun apsd */ if (chg->ok_to_pd) { chg->ok_to_pd = false; rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return rc; } smblib_rerun_apsd(chg); } } smblib_update_usb_type(chg); Loading @@ -2338,15 +2309,6 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) return rc; } int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val) { if (!get_effective_result(chg->pd_allowed_votable)) return -EINVAL; return __smblib_set_prop_pd_active(chg, val->intval); } int smblib_set_prop_ship_mode(struct smb_charger *chg, const union power_supply_propval *val) { Loading Loading @@ -2657,11 +2619,7 @@ irqreturn_t icl_change_irq_handler(int irq, void *data) static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising) { if (vbus_rising) { /* use the typec flag even though its not typec */ chg->typec_present = 1; } else { chg->typec_present = 0; if (!vbus_rising) { smblib_update_usb_type(chg); smblib_notify_device_mode(chg, false); smblib_uusb_removal(chg); Loading Loading @@ -2764,12 +2722,10 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data) struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; mutex_lock(&chg->lock); if (chg->pd_hard_reset) smblib_usb_plugin_hard_reset_locked(chg); else smblib_usb_plugin_locked(chg); mutex_unlock(&chg->lock); return IRQ_HANDLED; } Loading Loading @@ -2858,8 +2814,6 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (!rising) return; vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); if (chg->mode == PARALLEL_MASTER) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); Loading @@ -2872,33 +2826,19 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, bool rising, bool qc_charger) { const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* Hold off PD only until hvdcp 2.0 detection timeout */ if (rising) { /* enable HDC and ICL irq for QC2/3 charger */ if (qc_charger) vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0); else vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); /* * HVDCP detection timeout done * If adapter is not QC2.0/QC3.0 - it is a plain old DCP. * enforce DCP ICL if specified */ if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT)) /* enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); /* * if pd is not allowed, then set pd_active = false right here, * so that it starts the hvdcp engine */ if (!get_effective_result(chg->pd_allowed_votable)) __smblib_set_prop_pd_active(chg, 0); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__, Loading Loading @@ -2926,19 +2866,11 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: case FLOAT_CHARGER_BIT: /* if not DCP then no hvdcp timeout happens. Enable pd here */ vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) || chg->use_extcon) smblib_notify_device_mode(chg, true); break; case OCP_CHARGER_BIT: vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); /* if not DCP then no hvdcp timeout happens, Enable pd here. */ vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); break; case DCP_CHARGER_BIT: vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); break; Loading @@ -2957,6 +2889,14 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) int rc = 0; u8 stat; /* * Prepared to run PD or PD is active. At this moment, APSD is disabled, * but there still can be irq on apsd_done from previously unfinished * APSD run, skip it. */ if (chg->ok_to_pd) return IRQ_HANDLED; rc = smblib_read(chg, APSD_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc); Loading Loading @@ -3011,32 +2951,68 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) static void typec_sink_insertion(struct smb_charger *chg) { /* when a sink is inserted we should not wait on hvdcp timeout to * enable pd */ vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); vote(chg->usb_icl_votable, OTG_VOTER, true, 0); if (chg->use_extcon) { smblib_notify_usb_host(chg, true); chg->otg_present = true; } if (!chg->pr_swap_in_progress) chg->ok_to_pd = !(*chg->pd_disabled) || chg->early_usb_attach; } static void typec_src_insertion(struct smb_charger *chg) { int rc = 0; u8 stat; if (chg->pr_swap_in_progress) return; rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", rc); return; } chg->typec_legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; chg->ok_to_pd = !(chg->typec_legacy || *chg->pd_disabled) || chg->early_usb_attach; if (!chg->ok_to_pd) { rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return; } smblib_rerun_apsd(chg); } } static void typec_sink_removal(struct smb_charger *chg) { smblib_set_charge_param(chg, &chg->param.freq_switcher, chg->chg_freq.freq_above_otg_threshold); chg->boost_current_ua = 0; vote(chg->usb_icl_votable, OTG_VOTER, false, 0); } static void smblib_handle_typec_removal(struct smb_charger *chg) static void typec_src_removal(struct smb_charger *chg) { int rc; struct smb_irq_data *data; struct storm_watch *wdata; rc = smblib_request_dpdm(chg, false); /* disable apsd */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc); smblib_update_usb_type(chg); if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; Loading @@ -3062,11 +3038,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->usb_icl_votable, CTM_VOTER, false, 0); vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0); /* reset power delivery voters */ vote(chg->pd_allowed_votable, PD_VOTER, false, 0); vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0); /* reset usb irq voters */ vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0); Loading @@ -3078,14 +3049,10 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); chg->vconn_attempts = 0; chg->otg_attempts = 0; chg->pulse_cnt = 0; chg->usb_icl_delta_ua = 0; chg->voltage_min_uv = MICRO_5V; chg->voltage_max_uv = MICRO_5V; chg->pd_active = 0; chg->pd_hard_reset = 0; /* write back the default FLOAT charger configuration */ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, Loading @@ -3094,12 +3061,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't write float charger options rc=%d\n", rc); /* reset back to 103mS tCC debounce */ rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG, REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc); /* reconfigure allowed voltage for HVDCP */ rc = smblib_set_adapter_allowance(chg, USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V); Loading @@ -3107,58 +3068,15 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n", rc); /* enable DRP */ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, TYPEC_POWER_ROLE_CMD_MASK, 0); if (rc < 0) smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); /* HW controlled CC_OUT */ rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, TYPEC_CCOUT_SRC_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc); /* clear exit sink based on cc */ rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, EXIT_SNK_BASED_ON_CC_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n", rc); typec_sink_removal(chg); smblib_update_usb_type(chg); if (chg->use_extcon) { if (chg->otg_present) smblib_notify_usb_host(chg, false); else smblib_notify_device_mode(chg, false); } chg->otg_present = false; } static void smblib_handle_typec_insertion(struct smb_charger *chg) { int rc; u8 stat; vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0); rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return; } if (stat & SNK_SRC_MODE_BIT) { typec_sink_insertion(chg); } else { rc = smblib_request_dpdm(chg, true); if (rc < 0) smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); typec_sink_removal(chg); } chg->otg_present = false; chg->typec_legacy = false; } static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) Loading Loading @@ -3200,98 +3118,102 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua); } static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) { u8 stat; int typec_mode, rc; if (chg->pr_swap_in_progress) return; typec_mode = smblib_get_prop_typec_mode(chg); if (chg->typec_present && (typec_mode != chg->typec_mode)) smblib_handle_rp_change(chg, typec_mode); chg->typec_mode = typec_mode; if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) { chg->typec_present = true; smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n", smblib_typec_mode_name[chg->typec_mode]); smblib_handle_typec_insertion(chg); } else if (chg->typec_present && chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) { chg->typec_present = false; smblib_dbg(chg, PR_MISC, "TypeC removal\n"); smblib_handle_typec_removal(chg); } struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { cancel_delayed_work_sync(&chg->uusb_otg_work); vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); schedule_delayed_work(&chg->uusb_otg_work, msecs_to_jiffies(chg->otg_delay_ms)); return IRQ_HANDLED; } /* suspend usb if sink */ if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present) vote(chg->usb_icl_votable, OTG_VOTER, true, 0); else vote(chg->usb_icl_votable, OTG_VOTER, false, 0); smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", smblib_typec_mode_name[chg->typec_mode]); return IRQ_HANDLED; } static void smblib_usb_typec_change(struct smb_charger *chg) irqreturn_t typec_state_change_irq_handler(int irq, void *data) { int rc; u8 stat; smblib_handle_typec_cc_state_change(chg); struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; int typec_mode; rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { smblib_dbg(chg, PR_INTERRUPT, "Ignoring for micro USB\n"); return IRQ_HANDLED; } if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); typec_mode = smblib_get_prop_typec_mode(chg); if (chg->sink_src_mode != UNATTACHED_MODE && (typec_mode != chg->typec_mode)) smblib_handle_rp_change(chg, typec_mode); chg->typec_mode = typec_mode; smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", smblib_typec_mode_name[chg->typec_mode]); power_supply_changed(chg->usb_psy); return IRQ_HANDLED; } irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; u8 stat; int rc; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { cancel_delayed_work_sync(&chg->uusb_otg_work); vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); schedule_delayed_work(&chg->uusb_otg_work, msecs_to_jiffies(chg->otg_delay_ms)); smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", rc); return IRQ_HANDLED; } if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) { rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n", rc); return IRQ_HANDLED; } irqreturn_t typec_state_change_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; if (stat & SNK_SRC_MODE_BIT) { chg->sink_src_mode = SRC_MODE; typec_sink_insertion(chg); } else { chg->sink_src_mode = SINK_MODE; typec_src_insertion(chg); } if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) || chg->pr_swap_in_progress) { smblib_dbg(chg, PR_INTERRUPT, "Ignoring since pr_swap_in_progress\n"); return IRQ_HANDLED; } else { switch (chg->sink_src_mode) { case SRC_MODE: typec_sink_removal(chg); break; case SINK_MODE: typec_src_removal(chg); break; default: break; } mutex_lock(&chg->lock); smblib_usb_typec_change(chg); mutex_unlock(&chg->lock); if (!chg->pr_swap_in_progress) { chg->ok_to_pd = false; chg->sink_src_mode = UNATTACHED_MODE; chg->early_usb_attach = false; } } power_supply_changed(chg->usb_psy); return IRQ_HANDLED; } Loading Loading @@ -3717,23 +3639,6 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } chg->pd_disallowed_votable_indirect = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY, smblib_pd_disallowed_votable_indirect_callback, chg); if (IS_ERR(chg->pd_disallowed_votable_indirect)) { rc = PTR_ERR(chg->pd_disallowed_votable_indirect); chg->pd_disallowed_votable_indirect = NULL; return rc; } chg->pd_allowed_votable = create_votable("PD_ALLOWED", VOTE_SET_ANY, NULL, NULL); if (IS_ERR(chg->pd_allowed_votable)) { rc = PTR_ERR(chg->pd_allowed_votable); chg->pd_allowed_votable = NULL; return rc; } chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY, smblib_awake_vote_callback, chg); Loading Loading @@ -3771,10 +3676,6 @@ static void smblib_destroy_votables(struct smb_charger *chg) destroy_votable(chg->dc_suspend_votable); if (chg->usb_icl_votable) destroy_votable(chg->usb_icl_votable); if (chg->pd_disallowed_votable_indirect) destroy_votable(chg->pd_disallowed_votable_indirect); if (chg->pd_allowed_votable) destroy_votable(chg->pd_allowed_votable); if (chg->awake_votable) destroy_votable(chg->awake_votable); if (chg->chg_disable_votable) Loading @@ -3786,7 +3687,6 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->lock); mutex_init(&chg->otg_oc_lock); INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->pl_update_work, pl_update_work); INIT_WORK(&chg->jeita_update_work, jeita_update_work); Loading @@ -3799,6 +3699,7 @@ int smblib_init(struct smb_charger *chg) chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; chg->jeita_configured = false; chg->sink_src_mode = UNATTACHED_MODE; switch (chg->mode) { case PARALLEL_MASTER: Loading drivers/power/supply/qcom/smb5-lib.h +17 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes drivers/power/supply/qcom/smb5-reg.h +5 −0 Original line number Diff line number Diff line Loading @@ -215,6 +215,7 @@ enum { #define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6) #define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5) #define BC1P2_SRC_DETECT_BIT BIT(3) #define HVDCP_EN_BIT BIT(2) #define USBIN_OPTIONS_2_CFG_REG (USBIN_BASE + 0x63) #define FLOAT_OPTIONS_MASK GENMASK(2, 0) Loading Loading @@ -262,6 +263,9 @@ enum { #define SRC_RA_OPEN_BIT BIT(1) #define AUDIO_ACCESS_RA_RA_BIT BIT(0) #define TYPE_C_STATE_MACHINE_STATUS_REG (TYPEC_BASE + 0x09) #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) #define SNK_SRC_MODE_BIT BIT(6) #define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4) Loading @@ -269,6 +273,7 @@ enum { #define CC_ATTACHED_BIT BIT(0) #define LEGACY_CABLE_STATUS_REG (TYPEC_BASE + 0x0D) #define TYPEC_LEGACY_CABLE_STATUS_BIT BIT(1) #define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT BIT(0) #define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F) Loading Loading
drivers/power/supply/qcom/qpnp-smb5.c +44 −41 Original line number Diff line number Diff line Loading @@ -177,6 +177,11 @@ module_param_named( debug_mask, __debug_mask, int, 0600 ); static int __pd_disabled; module_param_named( pd_disabled, __pd_disabled, int, 0600 ); static int __weak_chg_icl_ua = 500000; module_param_named( weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600 Loading Loading @@ -434,7 +439,6 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_MODE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, Loading Loading @@ -515,9 +519,6 @@ static int smb5_usb_get_prop(struct power_supply *psy, else rc = smblib_get_prop_typec_cc_orientation(chg, val); break; case POWER_SUPPLY_PROP_PD_ALLOWED: rc = smblib_get_prop_pd_allowed(chg, val); break; case POWER_SUPPLY_PROP_PD_ACTIVE: val->intval = chg->pd_active; break; Loading Loading @@ -605,12 +606,6 @@ static int smb5_usb_set_prop(struct power_supply *psy, struct smb_charger *chg = &chip->chg; int rc = 0; mutex_lock(&chg->lock); if (!chg->typec_present) { rc = -EINVAL; goto unlock; } switch (psp) { case POWER_SUPPLY_PROP_PD_CURRENT_MAX: rc = smblib_set_prop_pd_current_max(chg, val); Loading Loading @@ -652,8 +647,6 @@ static int smb5_usb_set_prop(struct power_supply *psy, break; } unlock: mutex_unlock(&chg->lock); return rc; } Loading Loading @@ -1425,6 +1418,15 @@ static int smb5_configure_typec(struct smb_charger *chg) { int rc; /* disable apsd */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return rc; } rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG, TYPEC_CCOUT_DETACH_INT_EN_BIT | TYPEC_CCOUT_ATTACH_INT_EN_BIT); Loading Loading @@ -1459,14 +1461,6 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) { int rc; /* configure micro USB mode */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc); return rc; } rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, MICRO_USB_STATE_CHANGE_INT_EN_BIT, MICRO_USB_STATE_CHANGE_INT_EN_BIT); Loading Loading @@ -1500,7 +1494,6 @@ static int smb5_init_hw(struct smb5 *chip) &chg->default_icl_ua); /* Use SW based VBUS control, disable HW autonomous mode */ /* TODO: auth can be enabled through vote based on APSD flow */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, HVDCP_AUTH_ALG_EN_CFG_BIT); Loading Loading @@ -1537,10 +1530,22 @@ static int smb5_init_hw(struct smb5 *chip) type = !!(val & EN_MICRO_USB_MODE_BIT); } chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB : POWER_SUPPLY_CONNECTOR_TYPEC; pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC"); if (type) { chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; smblib_rerun_apsd_if_required(chg); rc = smb5_configure_micro_usb(chg); } else { chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC; rc = smb5_configure_typec(chg); } if (rc < 0) { dev_err(chg->dev, "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc); return rc; } /* * PMI632 based hw init: * - Initialize flash module for PMI632 Loading @@ -1548,8 +1553,6 @@ static int smb5_init_hw(struct smb5 *chip) if (chg->smb_version == PMI632_SUBTYPE) schgm_flash_init(chg); smblib_rerun_apsd_if_required(chg); /* vote 0mA on usb_icl for non battery platforms */ vote(chg->usb_icl_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); Loading @@ -1565,12 +1568,6 @@ static int smb5_init_hw(struct smb5 *chip) vote(chg->fv_votable, BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0, chg->batt_profile_fv_uv); vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER, chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0); /* Some h/w limit maximum supported ICL */ vote(chg->usb_icl_votable, HW_LIMIT_VOTER, Loading @@ -1594,16 +1591,6 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) rc = smb5_configure_micro_usb(chg); else rc = smb5_configure_typec(chg); if (rc < 0) { dev_err(chg->dev, "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc); return rc; } /* configure VBUS for software control */ rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0); if (rc < 0) { Loading Loading @@ -1812,11 +1799,21 @@ static int smb5_determine_initial_status(struct smb5 *chip) { struct smb_irq_data irq_data = {chip, "determine-initial-status"}; struct smb_charger *chg = &chip->chg; union power_supply_propval val; int rc; rc = smblib_get_prop_usb_present(chg, &val); if (rc < 0) { pr_err("Couldn't get usb present rc=%d\n", rc); return rc; } chg->early_usb_attach = val.intval; if (chg->bms_psy) smblib_suspend_on_debug_battery(chg); usb_plugin_irq_handler(0, &irq_data); typec_attach_detach_irq_handler(0, &irq_data); typec_state_change_irq_handler(0, &irq_data); usb_source_change_irq_handler(0, &irq_data); chg_state_change_irq_handler(0, &irq_data); Loading Loading @@ -2008,6 +2005,7 @@ static struct smb_irq_info smb5_irqs[] = { }, [TYPEC_ATTACH_DETACH_IRQ] = { .name = "typec-attach-detach", .handler = typec_attach_detach_irq_handler, }, [TYPEC_LEGACY_CABLE_DETECT_IRQ] = { .name = "typec-legacy-cable-detect", Loading Loading @@ -2303,6 +2301,7 @@ static int smb5_probe(struct platform_device *pdev) chg = &chip->chg; chg->dev = &pdev->dev; chg->debug_mask = &__debug_mask; chg->pd_disabled = &__pd_disabled; chg->weak_chg_icl_ua = &__weak_chg_icl_ua; chg->mode = PARALLEL_MASTER; chg->irq_info = smb5_irqs; Loading Loading @@ -2452,6 +2451,10 @@ static int smb5_remove(struct platform_device *pdev) struct smb5 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; /* force enable APSD */ smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT); smb5_free_interrupts(chg); smblib_deinit(chg); platform_set_drvdata(pdev, NULL); Loading
drivers/power/supply/qcom/smb5-lib.c +149 −248 Original line number Diff line number Diff line Loading @@ -663,10 +663,6 @@ static void smblib_uusb_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc); if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; if (data) { Loading Loading @@ -954,18 +950,6 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, (bool)suspend); } static int smblib_pd_disallowed_votable_indirect_callback( struct votable *votable, void *data, int disallowed, const char *client) { struct smb_charger *chg = data; int rc; rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER, !disallowed, 0); return rc; } static int smblib_awake_vote_callback(struct votable *votable, void *data, int awake, const char *client) { Loading Loading @@ -1989,13 +1973,6 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, return rc; } int smblib_get_prop_pd_allowed(struct smb_charger *chg, union power_supply_propval *val) { val->intval = get_effective_result(chg->pd_allowed_votable); return 0; } int smblib_get_prop_input_current_settled(struct smb_charger *chg, union power_supply_propval *val) { Loading Loading @@ -2039,13 +2016,7 @@ int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg, int smblib_get_pe_start(struct smb_charger *chg, union power_supply_propval *val) { /* * hvdcp timeout voter is the last one to allow pd. Use its vote * to indicate start of pe engine */ val->intval = !get_client_vote_locked(chg->pd_disallowed_votable_indirect, APSD_VOTER); val->intval = chg->ok_to_pd; return 0; } Loading Loading @@ -2298,14 +2269,14 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg, return rc; } static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val) { int rc = 0; chg->pd_active = pd_active; chg->pd_active = val->intval; if (chg->pd_active) { vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); /* Loading @@ -2313,24 +2284,24 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) * It is guaranteed that pd_active is set prior to * pd_current_max */ rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); if (rc < 0) smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n", rc); /* clear USB ICL vote for DCP_VOTER */ rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); if (rc < 0) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); /* remove USB_PSY_VOTER */ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); if (rc < 0) smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc); vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); } else { vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); /* PD hard resets failed, rerun apsd */ if (chg->ok_to_pd) { chg->ok_to_pd = false; rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return rc; } smblib_rerun_apsd(chg); } } smblib_update_usb_type(chg); Loading @@ -2338,15 +2309,6 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) return rc; } int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val) { if (!get_effective_result(chg->pd_allowed_votable)) return -EINVAL; return __smblib_set_prop_pd_active(chg, val->intval); } int smblib_set_prop_ship_mode(struct smb_charger *chg, const union power_supply_propval *val) { Loading Loading @@ -2657,11 +2619,7 @@ irqreturn_t icl_change_irq_handler(int irq, void *data) static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising) { if (vbus_rising) { /* use the typec flag even though its not typec */ chg->typec_present = 1; } else { chg->typec_present = 0; if (!vbus_rising) { smblib_update_usb_type(chg); smblib_notify_device_mode(chg, false); smblib_uusb_removal(chg); Loading Loading @@ -2764,12 +2722,10 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data) struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; mutex_lock(&chg->lock); if (chg->pd_hard_reset) smblib_usb_plugin_hard_reset_locked(chg); else smblib_usb_plugin_locked(chg); mutex_unlock(&chg->lock); return IRQ_HANDLED; } Loading Loading @@ -2858,8 +2814,6 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (!rising) return; vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); if (chg->mode == PARALLEL_MASTER) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); Loading @@ -2872,33 +2826,19 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, bool rising, bool qc_charger) { const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* Hold off PD only until hvdcp 2.0 detection timeout */ if (rising) { /* enable HDC and ICL irq for QC2/3 charger */ if (qc_charger) vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0); else vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); /* * HVDCP detection timeout done * If adapter is not QC2.0/QC3.0 - it is a plain old DCP. * enforce DCP ICL if specified */ if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT)) /* enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); /* * if pd is not allowed, then set pd_active = false right here, * so that it starts the hvdcp engine */ if (!get_effective_result(chg->pd_allowed_votable)) __smblib_set_prop_pd_active(chg, 0); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__, Loading Loading @@ -2926,19 +2866,11 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: case FLOAT_CHARGER_BIT: /* if not DCP then no hvdcp timeout happens. Enable pd here */ vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) || chg->use_extcon) smblib_notify_device_mode(chg, true); break; case OCP_CHARGER_BIT: vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); /* if not DCP then no hvdcp timeout happens, Enable pd here. */ vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); break; case DCP_CHARGER_BIT: vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); break; Loading @@ -2957,6 +2889,14 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) int rc = 0; u8 stat; /* * Prepared to run PD or PD is active. At this moment, APSD is disabled, * but there still can be irq on apsd_done from previously unfinished * APSD run, skip it. */ if (chg->ok_to_pd) return IRQ_HANDLED; rc = smblib_read(chg, APSD_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc); Loading Loading @@ -3011,32 +2951,68 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) static void typec_sink_insertion(struct smb_charger *chg) { /* when a sink is inserted we should not wait on hvdcp timeout to * enable pd */ vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); vote(chg->usb_icl_votable, OTG_VOTER, true, 0); if (chg->use_extcon) { smblib_notify_usb_host(chg, true); chg->otg_present = true; } if (!chg->pr_swap_in_progress) chg->ok_to_pd = !(*chg->pd_disabled) || chg->early_usb_attach; } static void typec_src_insertion(struct smb_charger *chg) { int rc = 0; u8 stat; if (chg->pr_swap_in_progress) return; rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", rc); return; } chg->typec_legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; chg->ok_to_pd = !(chg->typec_legacy || *chg->pd_disabled) || chg->early_usb_attach; if (!chg->ok_to_pd) { rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return; } smblib_rerun_apsd(chg); } } static void typec_sink_removal(struct smb_charger *chg) { smblib_set_charge_param(chg, &chg->param.freq_switcher, chg->chg_freq.freq_above_otg_threshold); chg->boost_current_ua = 0; vote(chg->usb_icl_votable, OTG_VOTER, false, 0); } static void smblib_handle_typec_removal(struct smb_charger *chg) static void typec_src_removal(struct smb_charger *chg) { int rc; struct smb_irq_data *data; struct storm_watch *wdata; rc = smblib_request_dpdm(chg, false); /* disable apsd */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc); smblib_update_usb_type(chg); if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; Loading @@ -3062,11 +3038,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->usb_icl_votable, CTM_VOTER, false, 0); vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0); /* reset power delivery voters */ vote(chg->pd_allowed_votable, PD_VOTER, false, 0); vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0); /* reset usb irq voters */ vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0); Loading @@ -3078,14 +3049,10 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); chg->vconn_attempts = 0; chg->otg_attempts = 0; chg->pulse_cnt = 0; chg->usb_icl_delta_ua = 0; chg->voltage_min_uv = MICRO_5V; chg->voltage_max_uv = MICRO_5V; chg->pd_active = 0; chg->pd_hard_reset = 0; /* write back the default FLOAT charger configuration */ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, Loading @@ -3094,12 +3061,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't write float charger options rc=%d\n", rc); /* reset back to 103mS tCC debounce */ rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG, REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc); /* reconfigure allowed voltage for HVDCP */ rc = smblib_set_adapter_allowance(chg, USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V); Loading @@ -3107,58 +3068,15 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n", rc); /* enable DRP */ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, TYPEC_POWER_ROLE_CMD_MASK, 0); if (rc < 0) smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); /* HW controlled CC_OUT */ rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, TYPEC_CCOUT_SRC_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc); /* clear exit sink based on cc */ rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, EXIT_SNK_BASED_ON_CC_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n", rc); typec_sink_removal(chg); smblib_update_usb_type(chg); if (chg->use_extcon) { if (chg->otg_present) smblib_notify_usb_host(chg, false); else smblib_notify_device_mode(chg, false); } chg->otg_present = false; } static void smblib_handle_typec_insertion(struct smb_charger *chg) { int rc; u8 stat; vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0); rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return; } if (stat & SNK_SRC_MODE_BIT) { typec_sink_insertion(chg); } else { rc = smblib_request_dpdm(chg, true); if (rc < 0) smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); typec_sink_removal(chg); } chg->otg_present = false; chg->typec_legacy = false; } static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) Loading Loading @@ -3200,98 +3118,102 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua); } static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) { u8 stat; int typec_mode, rc; if (chg->pr_swap_in_progress) return; typec_mode = smblib_get_prop_typec_mode(chg); if (chg->typec_present && (typec_mode != chg->typec_mode)) smblib_handle_rp_change(chg, typec_mode); chg->typec_mode = typec_mode; if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) { chg->typec_present = true; smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n", smblib_typec_mode_name[chg->typec_mode]); smblib_handle_typec_insertion(chg); } else if (chg->typec_present && chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) { chg->typec_present = false; smblib_dbg(chg, PR_MISC, "TypeC removal\n"); smblib_handle_typec_removal(chg); } struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { cancel_delayed_work_sync(&chg->uusb_otg_work); vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); schedule_delayed_work(&chg->uusb_otg_work, msecs_to_jiffies(chg->otg_delay_ms)); return IRQ_HANDLED; } /* suspend usb if sink */ if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present) vote(chg->usb_icl_votable, OTG_VOTER, true, 0); else vote(chg->usb_icl_votable, OTG_VOTER, false, 0); smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", smblib_typec_mode_name[chg->typec_mode]); return IRQ_HANDLED; } static void smblib_usb_typec_change(struct smb_charger *chg) irqreturn_t typec_state_change_irq_handler(int irq, void *data) { int rc; u8 stat; smblib_handle_typec_cc_state_change(chg); struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; int typec_mode; rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); return; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { smblib_dbg(chg, PR_INTERRUPT, "Ignoring for micro USB\n"); return IRQ_HANDLED; } if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); typec_mode = smblib_get_prop_typec_mode(chg); if (chg->sink_src_mode != UNATTACHED_MODE && (typec_mode != chg->typec_mode)) smblib_handle_rp_change(chg, typec_mode); chg->typec_mode = typec_mode; smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", smblib_typec_mode_name[chg->typec_mode]); power_supply_changed(chg->usb_psy); return IRQ_HANDLED; } irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; u8 stat; int rc; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { cancel_delayed_work_sync(&chg->uusb_otg_work); vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); schedule_delayed_work(&chg->uusb_otg_work, msecs_to_jiffies(chg->otg_delay_ms)); smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", rc); return IRQ_HANDLED; } if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) { rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n", rc); return IRQ_HANDLED; } irqreturn_t typec_state_change_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; if (stat & SNK_SRC_MODE_BIT) { chg->sink_src_mode = SRC_MODE; typec_sink_insertion(chg); } else { chg->sink_src_mode = SINK_MODE; typec_src_insertion(chg); } if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) || chg->pr_swap_in_progress) { smblib_dbg(chg, PR_INTERRUPT, "Ignoring since pr_swap_in_progress\n"); return IRQ_HANDLED; } else { switch (chg->sink_src_mode) { case SRC_MODE: typec_sink_removal(chg); break; case SINK_MODE: typec_src_removal(chg); break; default: break; } mutex_lock(&chg->lock); smblib_usb_typec_change(chg); mutex_unlock(&chg->lock); if (!chg->pr_swap_in_progress) { chg->ok_to_pd = false; chg->sink_src_mode = UNATTACHED_MODE; chg->early_usb_attach = false; } } power_supply_changed(chg->usb_psy); return IRQ_HANDLED; } Loading Loading @@ -3717,23 +3639,6 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } chg->pd_disallowed_votable_indirect = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY, smblib_pd_disallowed_votable_indirect_callback, chg); if (IS_ERR(chg->pd_disallowed_votable_indirect)) { rc = PTR_ERR(chg->pd_disallowed_votable_indirect); chg->pd_disallowed_votable_indirect = NULL; return rc; } chg->pd_allowed_votable = create_votable("PD_ALLOWED", VOTE_SET_ANY, NULL, NULL); if (IS_ERR(chg->pd_allowed_votable)) { rc = PTR_ERR(chg->pd_allowed_votable); chg->pd_allowed_votable = NULL; return rc; } chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY, smblib_awake_vote_callback, chg); Loading Loading @@ -3771,10 +3676,6 @@ static void smblib_destroy_votables(struct smb_charger *chg) destroy_votable(chg->dc_suspend_votable); if (chg->usb_icl_votable) destroy_votable(chg->usb_icl_votable); if (chg->pd_disallowed_votable_indirect) destroy_votable(chg->pd_disallowed_votable_indirect); if (chg->pd_allowed_votable) destroy_votable(chg->pd_allowed_votable); if (chg->awake_votable) destroy_votable(chg->awake_votable); if (chg->chg_disable_votable) Loading @@ -3786,7 +3687,6 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->lock); mutex_init(&chg->otg_oc_lock); INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->pl_update_work, pl_update_work); INIT_WORK(&chg->jeita_update_work, jeita_update_work); Loading @@ -3799,6 +3699,7 @@ int smblib_init(struct smb_charger *chg) chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; chg->jeita_configured = false; chg->sink_src_mode = UNATTACHED_MODE; switch (chg->mode) { case PARALLEL_MASTER: Loading
drivers/power/supply/qcom/smb5-lib.h +17 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes
drivers/power/supply/qcom/smb5-reg.h +5 −0 Original line number Diff line number Diff line Loading @@ -215,6 +215,7 @@ enum { #define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6) #define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5) #define BC1P2_SRC_DETECT_BIT BIT(3) #define HVDCP_EN_BIT BIT(2) #define USBIN_OPTIONS_2_CFG_REG (USBIN_BASE + 0x63) #define FLOAT_OPTIONS_MASK GENMASK(2, 0) Loading Loading @@ -262,6 +263,9 @@ enum { #define SRC_RA_OPEN_BIT BIT(1) #define AUDIO_ACCESS_RA_RA_BIT BIT(0) #define TYPE_C_STATE_MACHINE_STATUS_REG (TYPEC_BASE + 0x09) #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) #define SNK_SRC_MODE_BIT BIT(6) #define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4) Loading @@ -269,6 +273,7 @@ enum { #define CC_ATTACHED_BIT BIT(0) #define LEGACY_CABLE_STATUS_REG (TYPEC_BASE + 0x0D) #define TYPEC_LEGACY_CABLE_STATUS_BIT BIT(1) #define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT BIT(0) #define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F) Loading