Loading drivers/power/supply/qcom/qpnp-smb5.c +6 −0 Original line number Diff line number Diff line Loading @@ -2610,6 +2610,12 @@ static int smb5_probe(struct platform_device *pdev) return rc; } if (alarmtimer_get_rtcdev()) alarm_init(&chg->lpd_recheck_timer, ALARM_REALTIME, smblib_lpd_recheck_timer); else return -EPROBE_DEFER; rc = smblib_init(chg); if (rc < 0) { pr_err("Smblib_init failed rc=%d\n", rc); Loading drivers/power/supply/qcom/smb5-lib.c +219 −0 Original line number Diff line number Diff line Loading @@ -2299,6 +2299,9 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg) int rc; u8 stat; if (chg->lpd_stage == LPD_STAGE_COMMIT) return POWER_SUPPLY_TYPEC_NONE; rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n", Loading Loading @@ -3661,6 +3664,84 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, ktime_t time) { union power_supply_propval pval; struct smb_charger *chg = container_of(alarm, struct smb_charger, lpd_recheck_timer); int rc; if (chg->lpd_reason == LPD_MOISTURE_DETECTED) { pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); return ALARMTIMER_NORESTART; } } else { rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT, TYPEC_WATER_DETECTION_INT_EN_BIT); if (rc < 0) { smblib_err(chg, "Couldn't set TYPE_C_INTERRUPT_EN_CFG_2_REG rc=%d\n", rc); return ALARMTIMER_NORESTART; } } chg->lpd_stage = LPD_STAGE_NONE; chg->lpd_reason = LPD_NONE; return ALARMTIMER_NORESTART; } #define RSBU_K_300K_UV 3000000 static bool smblib_src_lpd(struct smb_charger *chg) { union power_supply_propval pval; bool lpd_flag = false; u8 stat; int rc; rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n", rc); return false; } switch (stat & DETECTED_SNK_TYPE_MASK) { case SRC_DEBUG_ACCESS_BIT: if (smblib_rsbux_low(chg, RSBU_K_300K_UV)) lpd_flag = true; break; case SRC_RD_RA_VCONN_BIT: case SRC_RD_OPEN_BIT: case AUDIO_ACCESS_RA_RA_BIT: default: break; } if (lpd_flag) { chg->lpd_stage = LPD_STAGE_COMMIT; pval.intval = POWER_SUPPLY_TYPEC_PR_SINK; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); chg->lpd_reason = LPD_MOISTURE_DETECTED; alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(60000)); } else { chg->lpd_reason = LPD_NONE; chg->typec_mode = smblib_get_prop_typec_mode(chg); } return lpd_flag; } static void typec_sink_insertion(struct smb_charger *chg) { vote(chg->usb_icl_votable, OTG_VOTER, true, 0); Loading Loading @@ -3845,6 +3926,10 @@ irqreturn_t typec_or_rid_detection_change_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; smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { cancel_delayed_work_sync(&chg->uusb_otg_work); Loading @@ -3855,6 +3940,26 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } if (chg->pr_swap_in_progress || chg->pd_hard_reset) return IRQ_HANDLED; 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; } /* liquid presence detected, to check further */ if ((stat & TYPEC_WATER_DETECTION_STATUS_BIT) && chg->lpd_stage == LPD_STAGE_NONE) { chg->lpd_stage = LPD_STAGE_FLOAT; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, true, 0); schedule_delayed_work(&chg->lpd_ra_open_work, msecs_to_jiffies(300)); } return IRQ_HANDLED; } Loading Loading @@ -3902,6 +4007,10 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) } if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) { chg->lpd_stage = LPD_STAGE_ATTACHED; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, false, 0); 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", Loading @@ -3910,6 +4019,8 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) } if (stat & SNK_SRC_MODE_BIT) { if (smblib_src_lpd(chg)) return IRQ_HANDLED; chg->sink_src_mode = SRC_MODE; typec_sink_insertion(chg); } else { Loading @@ -3934,6 +4045,10 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) chg->sink_src_mode = UNATTACHED_MODE; chg->early_usb_attach = false; } chg->lpd_stage = LPD_STAGE_DETACHED; schedule_delayed_work(&chg->lpd_detach_work, msecs_to_jiffies(100)); } power_supply_changed(chg->usb_psy); Loading Loading @@ -4405,6 +4520,106 @@ static void jeita_update_work(struct work_struct *work) chg->jeita_configured = true; } static void smblib_lpd_ra_open_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, lpd_ra_open_work.work); union power_supply_propval pval; u8 stat; int rc; if (chg->pr_swap_in_progress || chg->pd_hard_reset) { chg->lpd_stage = LPD_STAGE_NONE; goto out; } if (chg->lpd_stage != LPD_STAGE_FLOAT) goto out; 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); goto out; } /* double check water detection status bit */ if (!(stat & TYPEC_WATER_DETECTION_STATUS_BIT)) { chg->lpd_stage = LPD_STAGE_NONE; goto out; } chg->lpd_stage = LPD_STAGE_COMMIT; /* Enable source only mode */ pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); goto out; } /* Wait 1.5ms to read src status */ usleep_range(1500, 1510); rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n", rc); goto out; } /* Emark cable */ if ((stat & SRC_RA_OPEN_BIT) && !smblib_rsbux_low(chg, RSBU_K_300K_UV)) { /* Floating cable, disable water detection irq temporarily */ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT, 0); if (rc < 0) { smblib_err(chg, "Couldn't set TYPE_C_INTERRUPT_EN_CFG_2_REG rc=%d\n", rc); goto out; } /* restore DRP mode */ pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); goto out; } chg->lpd_reason = LPD_FLOATING_CABLE; } else { /* Moisture detected, enable sink only mode */ pval.intval = POWER_SUPPLY_TYPEC_PR_SINK; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); goto out; } chg->lpd_reason = LPD_MOISTURE_DETECTED; } /* recheck in 60 seconds */ alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(60000)); out: vote(chg->awake_votable, LPD_VOTER, false, 0); } static void smblib_lpd_detach_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, lpd_detach_work.work); if (chg->lpd_stage == LPD_STAGE_DETACHED) chg->lpd_stage = LPD_STAGE_NONE; } static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; Loading Loading @@ -4528,6 +4743,8 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); INIT_DELAYED_WORK(&chg->lpd_ra_open_work, smblib_lpd_ra_open_work); INIT_DELAYED_WORK(&chg->lpd_detach_work, smblib_lpd_detach_work); chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; Loading Loading @@ -4628,6 +4845,8 @@ int smblib_deinit(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); cancel_delayed_work_sync(&chg->uusb_otg_work); cancel_delayed_work_sync(&chg->bb_removal_work); cancel_delayed_work_sync(&chg->lpd_ra_open_work); cancel_delayed_work_sync(&chg->lpd_detach_work); power_supply_unreg_notifier(&chg->nb); smblib_destroy_votables(chg); qcom_step_chg_deinit(); Loading drivers/power/supply/qcom/smb5-lib.h +25 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #ifndef __SMB5_CHARGER_H #define __SMB5_CHARGER_H #include <linux/alarmtimer.h> #include <linux/ktime.h> #include <linux/types.h> #include <linux/interrupt.h> #include <linux/irqreturn.h> Loading Loading @@ -60,6 +62,7 @@ enum print_reason { #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" #define PL_SMB_EN_VOTER "PL_SMB_EN_VOTER" #define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define LPD_VOTER "LPD_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 Loading Loading @@ -194,6 +197,20 @@ static const unsigned int smblib_extcon_cable[] = { EXTCON_NONE, }; enum lpd_reason { LPD_NONE, LPD_MOISTURE_DETECTED, LPD_FLOATING_CABLE, }; enum lpd_stage { LPD_STAGE_NONE, LPD_STAGE_FLOAT, LPD_STAGE_ATTACHED, LPD_STAGE_DETACHED, LPD_STAGE_COMMIT, }; /* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */ static const u32 smblib_extcon_exclusive[] = {0x3, 0}; Loading Loading @@ -325,6 +342,10 @@ struct smb_charger { struct delayed_work pl_enable_work; struct delayed_work uusb_otg_work; struct delayed_work bb_removal_work; struct delayed_work lpd_ra_open_work; struct delayed_work lpd_detach_work; struct alarm lpd_recheck_timer; /* secondary charger config */ bool sec_pl_present; Loading Loading @@ -376,6 +397,8 @@ struct smb_charger { int charger_temp_max; int smb_temp_max; u8 typec_try_mode; enum lpd_stage lpd_stage; enum lpd_reason lpd_reason; /* workaround flag */ u32 wa_flags; Loading Loading @@ -575,6 +598,8 @@ int smblib_get_prop_from_bms(struct smb_charger *chg, union power_supply_propval *val); int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable); int smblib_icl_override(struct smb_charger *chg, bool override); enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, ktime_t time); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); Loading drivers/power/supply/qcom/smb5-reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -308,6 +308,7 @@ enum { #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) #define TYPEC_WATER_DETECTION_STATUS_BIT BIT(7) #define SNK_SRC_MODE_BIT BIT(6) #define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4) #define CC_ORIENTATION_BIT BIT(1) Loading Loading
drivers/power/supply/qcom/qpnp-smb5.c +6 −0 Original line number Diff line number Diff line Loading @@ -2610,6 +2610,12 @@ static int smb5_probe(struct platform_device *pdev) return rc; } if (alarmtimer_get_rtcdev()) alarm_init(&chg->lpd_recheck_timer, ALARM_REALTIME, smblib_lpd_recheck_timer); else return -EPROBE_DEFER; rc = smblib_init(chg); if (rc < 0) { pr_err("Smblib_init failed rc=%d\n", rc); Loading
drivers/power/supply/qcom/smb5-lib.c +219 −0 Original line number Diff line number Diff line Loading @@ -2299,6 +2299,9 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg) int rc; u8 stat; if (chg->lpd_stage == LPD_STAGE_COMMIT) return POWER_SUPPLY_TYPEC_NONE; rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n", Loading Loading @@ -3661,6 +3664,84 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, ktime_t time) { union power_supply_propval pval; struct smb_charger *chg = container_of(alarm, struct smb_charger, lpd_recheck_timer); int rc; if (chg->lpd_reason == LPD_MOISTURE_DETECTED) { pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); return ALARMTIMER_NORESTART; } } else { rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT, TYPEC_WATER_DETECTION_INT_EN_BIT); if (rc < 0) { smblib_err(chg, "Couldn't set TYPE_C_INTERRUPT_EN_CFG_2_REG rc=%d\n", rc); return ALARMTIMER_NORESTART; } } chg->lpd_stage = LPD_STAGE_NONE; chg->lpd_reason = LPD_NONE; return ALARMTIMER_NORESTART; } #define RSBU_K_300K_UV 3000000 static bool smblib_src_lpd(struct smb_charger *chg) { union power_supply_propval pval; bool lpd_flag = false; u8 stat; int rc; rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n", rc); return false; } switch (stat & DETECTED_SNK_TYPE_MASK) { case SRC_DEBUG_ACCESS_BIT: if (smblib_rsbux_low(chg, RSBU_K_300K_UV)) lpd_flag = true; break; case SRC_RD_RA_VCONN_BIT: case SRC_RD_OPEN_BIT: case AUDIO_ACCESS_RA_RA_BIT: default: break; } if (lpd_flag) { chg->lpd_stage = LPD_STAGE_COMMIT; pval.intval = POWER_SUPPLY_TYPEC_PR_SINK; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); chg->lpd_reason = LPD_MOISTURE_DETECTED; alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(60000)); } else { chg->lpd_reason = LPD_NONE; chg->typec_mode = smblib_get_prop_typec_mode(chg); } return lpd_flag; } static void typec_sink_insertion(struct smb_charger *chg) { vote(chg->usb_icl_votable, OTG_VOTER, true, 0); Loading Loading @@ -3845,6 +3926,10 @@ irqreturn_t typec_or_rid_detection_change_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; smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { cancel_delayed_work_sync(&chg->uusb_otg_work); Loading @@ -3855,6 +3940,26 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } if (chg->pr_swap_in_progress || chg->pd_hard_reset) return IRQ_HANDLED; 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; } /* liquid presence detected, to check further */ if ((stat & TYPEC_WATER_DETECTION_STATUS_BIT) && chg->lpd_stage == LPD_STAGE_NONE) { chg->lpd_stage = LPD_STAGE_FLOAT; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, true, 0); schedule_delayed_work(&chg->lpd_ra_open_work, msecs_to_jiffies(300)); } return IRQ_HANDLED; } Loading Loading @@ -3902,6 +4007,10 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) } if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) { chg->lpd_stage = LPD_STAGE_ATTACHED; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, false, 0); 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", Loading @@ -3910,6 +4019,8 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) } if (stat & SNK_SRC_MODE_BIT) { if (smblib_src_lpd(chg)) return IRQ_HANDLED; chg->sink_src_mode = SRC_MODE; typec_sink_insertion(chg); } else { Loading @@ -3934,6 +4045,10 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) chg->sink_src_mode = UNATTACHED_MODE; chg->early_usb_attach = false; } chg->lpd_stage = LPD_STAGE_DETACHED; schedule_delayed_work(&chg->lpd_detach_work, msecs_to_jiffies(100)); } power_supply_changed(chg->usb_psy); Loading Loading @@ -4405,6 +4520,106 @@ static void jeita_update_work(struct work_struct *work) chg->jeita_configured = true; } static void smblib_lpd_ra_open_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, lpd_ra_open_work.work); union power_supply_propval pval; u8 stat; int rc; if (chg->pr_swap_in_progress || chg->pd_hard_reset) { chg->lpd_stage = LPD_STAGE_NONE; goto out; } if (chg->lpd_stage != LPD_STAGE_FLOAT) goto out; 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); goto out; } /* double check water detection status bit */ if (!(stat & TYPEC_WATER_DETECTION_STATUS_BIT)) { chg->lpd_stage = LPD_STAGE_NONE; goto out; } chg->lpd_stage = LPD_STAGE_COMMIT; /* Enable source only mode */ pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); goto out; } /* Wait 1.5ms to read src status */ usleep_range(1500, 1510); rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n", rc); goto out; } /* Emark cable */ if ((stat & SRC_RA_OPEN_BIT) && !smblib_rsbux_low(chg, RSBU_K_300K_UV)) { /* Floating cable, disable water detection irq temporarily */ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT, 0); if (rc < 0) { smblib_err(chg, "Couldn't set TYPE_C_INTERRUPT_EN_CFG_2_REG rc=%d\n", rc); goto out; } /* restore DRP mode */ pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); goto out; } chg->lpd_reason = LPD_FLOATING_CABLE; } else { /* Moisture detected, enable sink only mode */ pval.intval = POWER_SUPPLY_TYPEC_PR_SINK; rc = smblib_set_prop_typec_power_role(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); goto out; } chg->lpd_reason = LPD_MOISTURE_DETECTED; } /* recheck in 60 seconds */ alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(60000)); out: vote(chg->awake_votable, LPD_VOTER, false, 0); } static void smblib_lpd_detach_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, lpd_detach_work.work); if (chg->lpd_stage == LPD_STAGE_DETACHED) chg->lpd_stage = LPD_STAGE_NONE; } static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; Loading Loading @@ -4528,6 +4743,8 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); INIT_DELAYED_WORK(&chg->lpd_ra_open_work, smblib_lpd_ra_open_work); INIT_DELAYED_WORK(&chg->lpd_detach_work, smblib_lpd_detach_work); chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; Loading Loading @@ -4628,6 +4845,8 @@ int smblib_deinit(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); cancel_delayed_work_sync(&chg->uusb_otg_work); cancel_delayed_work_sync(&chg->bb_removal_work); cancel_delayed_work_sync(&chg->lpd_ra_open_work); cancel_delayed_work_sync(&chg->lpd_detach_work); power_supply_unreg_notifier(&chg->nb); smblib_destroy_votables(chg); qcom_step_chg_deinit(); Loading
drivers/power/supply/qcom/smb5-lib.h +25 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #ifndef __SMB5_CHARGER_H #define __SMB5_CHARGER_H #include <linux/alarmtimer.h> #include <linux/ktime.h> #include <linux/types.h> #include <linux/interrupt.h> #include <linux/irqreturn.h> Loading Loading @@ -60,6 +62,7 @@ enum print_reason { #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" #define PL_SMB_EN_VOTER "PL_SMB_EN_VOTER" #define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define LPD_VOTER "LPD_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 Loading Loading @@ -194,6 +197,20 @@ static const unsigned int smblib_extcon_cable[] = { EXTCON_NONE, }; enum lpd_reason { LPD_NONE, LPD_MOISTURE_DETECTED, LPD_FLOATING_CABLE, }; enum lpd_stage { LPD_STAGE_NONE, LPD_STAGE_FLOAT, LPD_STAGE_ATTACHED, LPD_STAGE_DETACHED, LPD_STAGE_COMMIT, }; /* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */ static const u32 smblib_extcon_exclusive[] = {0x3, 0}; Loading Loading @@ -325,6 +342,10 @@ struct smb_charger { struct delayed_work pl_enable_work; struct delayed_work uusb_otg_work; struct delayed_work bb_removal_work; struct delayed_work lpd_ra_open_work; struct delayed_work lpd_detach_work; struct alarm lpd_recheck_timer; /* secondary charger config */ bool sec_pl_present; Loading Loading @@ -376,6 +397,8 @@ struct smb_charger { int charger_temp_max; int smb_temp_max; u8 typec_try_mode; enum lpd_stage lpd_stage; enum lpd_reason lpd_reason; /* workaround flag */ u32 wa_flags; Loading Loading @@ -575,6 +598,8 @@ int smblib_get_prop_from_bms(struct smb_charger *chg, union power_supply_propval *val); int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable); int smblib_icl_override(struct smb_charger *chg, bool override); enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, ktime_t time); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); Loading
drivers/power/supply/qcom/smb5-reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -308,6 +308,7 @@ enum { #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) #define TYPEC_WATER_DETECTION_STATUS_BIT BIT(7) #define SNK_SRC_MODE_BIT BIT(6) #define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4) #define CC_ORIENTATION_BIT BIT(1) Loading