Loading drivers/power/supply/qcom/qpnp-smb2.c +6 −0 Original line number Diff line number Diff line Loading @@ -188,6 +188,11 @@ static int __weak_chg_icl_ua = 500000; module_param_named( weak_chg_icl_ua, __weak_chg_icl_ua, int, S_IRUSR | S_IWUSR); static int __try_sink_enabled = 1; module_param_named( try_sink_enabled, __try_sink_enabled, int, 0600 ); #define MICRO_1P5A 1500000 #define MICRO_P1A 100000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 Loading Loading @@ -2236,6 +2241,7 @@ static int smb2_probe(struct platform_device *pdev) chg->dev = &pdev->dev; chg->param = v1_params; chg->debug_mask = &__debug_mask; chg->try_sink_enabled = &__try_sink_enabled; chg->weak_chg_icl_ua = &__weak_chg_icl_ua; chg->mode = PARALLEL_MASTER; chg->irq_info = smb2_irqs; Loading drivers/power/supply/qcom/smb-lib.c +160 −2 Original line number Diff line number Diff line Loading @@ -3734,8 +3734,165 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) return IRQ_HANDLED; } static int typec_try_sink(struct smb_charger *chg) { union power_supply_propval val; bool debounce_done, vbus_detected, sink; u8 stat; int exit_mode = ATTACHED_SRC, rc; /* ignore typec interrupt while try.snk WIP */ chg->try_sink_active = true; /* force SNK mode */ val.intval = POWER_SUPPLY_TYPEC_PR_SINK; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) { smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc); goto try_sink_exit; } /* reduce Tccdebounce time to ~20ms */ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT); if (rc < 0) { smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc); goto try_sink_exit; } /* * give opportunity to the other side to be a SRC, * for tDRPTRY + Tccdebounce time */ msleep(100); rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); goto try_sink_exit; } debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT; if (!debounce_done) /* * The other side didn't switch to source, either it * is an adamant sink or is removed go back to showing Rp */ goto try_wait_src; /* * We are in force sink mode and the other side has switched to * showing Rp. Config DRP in case the other side removes Rp so we * can quickly (20ms) switch to showing our Rp. Note that the spec * needs us to show Rp for 80mS while the drp DFP residency is just * 54mS. But 54mS is plenty time for us to react and force Rp for * the remaining 26mS. */ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) { smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc); goto try_sink_exit; } /* * while other side is Rp, wait for VBUS from it; exit if other side * removes Rp */ do { rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); goto try_sink_exit; } debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT; vbus_detected = stat & TYPEC_VBUS_STATUS_BIT; /* Successfully transitioned to ATTACHED.SNK */ if (vbus_detected && debounce_done) { exit_mode = ATTACHED_SINK; goto try_sink_exit; } /* * Ensure sink since drp may put us in source if other * side switches back to Rd */ sink = !(stat & UFP_DFP_MODE_STATUS_BIT); usleep_range(1000, 2000); } while (debounce_done && sink); try_wait_src: /* * Transition to trywait.SRC state. check if other side still wants * to be SNK or has been removed. */ val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) { smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc); goto try_sink_exit; } /* Need to be in this state for tDRPTRY time, 75ms~150ms */ msleep(80); rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); goto try_sink_exit; } debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT; if (debounce_done) /* the other side wants to be a sink */ exit_mode = ATTACHED_SRC; else /* the other side is detached */ exit_mode = UNATTACHED_SINK; try_sink_exit: /* release forcing of SRC/SNK mode */ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc); /* revert Tccdebounce time back to ~120ms */ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc); chg->try_sink_active = false; return exit_mode; } static void typec_sink_insertion(struct smb_charger *chg) { int exit_mode; /* * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open * or RD-Ra for TccDebounce time. */ if (*chg->try_sink_enabled) { exit_mode = typec_try_sink(chg); if (exit_mode != ATTACHED_SRC) { smblib_usb_typec_change(chg); return; } } /* when a sink is inserted we should not wait on hvdcp timeout to * enable pd */ Loading Loading @@ -3993,7 +4150,7 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) smblib_typec_mode_name[chg->typec_mode]); } static void smblib_usb_typec_change(struct smb_charger *chg) void smblib_usb_typec_change(struct smb_charger *chg) { int rc; Loading Loading @@ -4029,7 +4186,8 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) return IRQ_HANDLED; } if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) { if (chg->cc2_detach_wa_active || chg->typec_en_dis_active || chg->try_sink_active) { smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n", chg->cc2_detach_wa_active ? "cc2_detach_wa" : "typec_en_dis"); Loading drivers/power/supply/qcom/smb-lib.h +9 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,12 @@ enum smb_irq_index { SMB_IRQ_MAX, }; enum try_sink_exit_mode { ATTACHED_SRC = 0, ATTACHED_SINK, UNATTACHED_SINK, }; struct smb_irq_info { const char *name; const irq_handler_t handler; Loading Loading @@ -232,6 +238,7 @@ struct smb_charger { struct smb_params param; struct smb_iio iio; int *debug_mask; int *try_sink_enabled; enum smb_mode mode; struct smb_chg_freq chg_freq; int smb_version; Loading Loading @@ -341,6 +348,7 @@ struct smb_charger { u32 wa_flags; bool cc2_detach_wa_active; bool typec_en_dis_active; bool try_sink_active; int boost_current_ua; int temp_speed_reading_count; Loading Loading @@ -518,6 +526,7 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); void smblib_usb_typec_change(struct smb_charger *chg); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); Loading Loading
drivers/power/supply/qcom/qpnp-smb2.c +6 −0 Original line number Diff line number Diff line Loading @@ -188,6 +188,11 @@ static int __weak_chg_icl_ua = 500000; module_param_named( weak_chg_icl_ua, __weak_chg_icl_ua, int, S_IRUSR | S_IWUSR); static int __try_sink_enabled = 1; module_param_named( try_sink_enabled, __try_sink_enabled, int, 0600 ); #define MICRO_1P5A 1500000 #define MICRO_P1A 100000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 Loading Loading @@ -2236,6 +2241,7 @@ static int smb2_probe(struct platform_device *pdev) chg->dev = &pdev->dev; chg->param = v1_params; chg->debug_mask = &__debug_mask; chg->try_sink_enabled = &__try_sink_enabled; chg->weak_chg_icl_ua = &__weak_chg_icl_ua; chg->mode = PARALLEL_MASTER; chg->irq_info = smb2_irqs; Loading
drivers/power/supply/qcom/smb-lib.c +160 −2 Original line number Diff line number Diff line Loading @@ -3734,8 +3734,165 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) return IRQ_HANDLED; } static int typec_try_sink(struct smb_charger *chg) { union power_supply_propval val; bool debounce_done, vbus_detected, sink; u8 stat; int exit_mode = ATTACHED_SRC, rc; /* ignore typec interrupt while try.snk WIP */ chg->try_sink_active = true; /* force SNK mode */ val.intval = POWER_SUPPLY_TYPEC_PR_SINK; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) { smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc); goto try_sink_exit; } /* reduce Tccdebounce time to ~20ms */ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT); if (rc < 0) { smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc); goto try_sink_exit; } /* * give opportunity to the other side to be a SRC, * for tDRPTRY + Tccdebounce time */ msleep(100); rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); goto try_sink_exit; } debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT; if (!debounce_done) /* * The other side didn't switch to source, either it * is an adamant sink or is removed go back to showing Rp */ goto try_wait_src; /* * We are in force sink mode and the other side has switched to * showing Rp. Config DRP in case the other side removes Rp so we * can quickly (20ms) switch to showing our Rp. Note that the spec * needs us to show Rp for 80mS while the drp DFP residency is just * 54mS. But 54mS is plenty time for us to react and force Rp for * the remaining 26mS. */ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) { smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc); goto try_sink_exit; } /* * while other side is Rp, wait for VBUS from it; exit if other side * removes Rp */ do { rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); goto try_sink_exit; } debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT; vbus_detected = stat & TYPEC_VBUS_STATUS_BIT; /* Successfully transitioned to ATTACHED.SNK */ if (vbus_detected && debounce_done) { exit_mode = ATTACHED_SINK; goto try_sink_exit; } /* * Ensure sink since drp may put us in source if other * side switches back to Rd */ sink = !(stat & UFP_DFP_MODE_STATUS_BIT); usleep_range(1000, 2000); } while (debounce_done && sink); try_wait_src: /* * Transition to trywait.SRC state. check if other side still wants * to be SNK or has been removed. */ val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) { smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc); goto try_sink_exit; } /* Need to be in this state for tDRPTRY time, 75ms~150ms */ msleep(80); rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); goto try_sink_exit; } debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT; if (debounce_done) /* the other side wants to be a sink */ exit_mode = ATTACHED_SRC; else /* the other side is detached */ exit_mode = UNATTACHED_SINK; try_sink_exit: /* release forcing of SRC/SNK mode */ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc); /* revert Tccdebounce time back to ~120ms */ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc); chg->try_sink_active = false; return exit_mode; } static void typec_sink_insertion(struct smb_charger *chg) { int exit_mode; /* * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open * or RD-Ra for TccDebounce time. */ if (*chg->try_sink_enabled) { exit_mode = typec_try_sink(chg); if (exit_mode != ATTACHED_SRC) { smblib_usb_typec_change(chg); return; } } /* when a sink is inserted we should not wait on hvdcp timeout to * enable pd */ Loading Loading @@ -3993,7 +4150,7 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) smblib_typec_mode_name[chg->typec_mode]); } static void smblib_usb_typec_change(struct smb_charger *chg) void smblib_usb_typec_change(struct smb_charger *chg) { int rc; Loading Loading @@ -4029,7 +4186,8 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) return IRQ_HANDLED; } if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) { if (chg->cc2_detach_wa_active || chg->typec_en_dis_active || chg->try_sink_active) { smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n", chg->cc2_detach_wa_active ? "cc2_detach_wa" : "typec_en_dis"); Loading
drivers/power/supply/qcom/smb-lib.h +9 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,12 @@ enum smb_irq_index { SMB_IRQ_MAX, }; enum try_sink_exit_mode { ATTACHED_SRC = 0, ATTACHED_SINK, UNATTACHED_SINK, }; struct smb_irq_info { const char *name; const irq_handler_t handler; Loading Loading @@ -232,6 +238,7 @@ struct smb_charger { struct smb_params param; struct smb_iio iio; int *debug_mask; int *try_sink_enabled; enum smb_mode mode; struct smb_chg_freq chg_freq; int smb_version; Loading Loading @@ -341,6 +348,7 @@ struct smb_charger { u32 wa_flags; bool cc2_detach_wa_active; bool typec_en_dis_active; bool try_sink_active; int boost_current_ua; int temp_speed_reading_count; Loading Loading @@ -518,6 +526,7 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); void smblib_usb_typec_change(struct smb_charger *chg); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); Loading