Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,12 @@ Charger specific properties: Definition: Boolean flag which when present disables suspend on collapse feature of charger hardware. - qcom,uusb-moisture-protection-enable Usage: optional Value type: bool Definition: Boolean flag which when present enables mositure protection feature for uUSB connector type. ============================================= Second Level Nodes - SMB5 Charger Peripherals ============================================= Loading drivers/power/supply/qcom/qpnp-smb5.c +41 −0 Original line number Diff line number Diff line Loading @@ -258,6 +258,8 @@ static int smb5_chg_config_init(struct smb5 *chip) chg->param = smb5_pm8150b_params; chg->name = "pm6150_charger"; chg->wa_flags |= SW_THERM_REGULATION_WA; if (pmic_rev_id->rev4 >= 2) chg->uusb_moisture_protection_enabled = true; chg->main_fcc_max = PM6150_MAX_FCC_UA; break; case PMI632_SUBTYPE: Loading Loading @@ -444,6 +446,11 @@ static int smb5_parse_dt(struct smb5 *chip) chg->fcc_stepper_enable = of_property_read_bool(node, "qcom,fcc-stepping-enable"); chg->uusb_moisture_protection_enabled = chg->uusb_moisture_protection_enabled && of_property_read_bool(node, "qcom,uusb-moisture-protection-enable"); /* Extract ADC channels */ rc = smblib_get_iio_channel(chg, "mid_voltage", &chg->iio.mid_chan); if (rc < 0) Loading Loading @@ -530,6 +537,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_SMB_EN_MODE, POWER_SUPPLY_PROP_SMB_EN_REASON, POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_MOISTURE_DETECTED, }; static int smb5_usb_get_prop(struct power_supply *psy, Loading Loading @@ -671,6 +679,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_SMB_EN_REASON: val->intval = chg->cp_reason; break; case POWER_SUPPLY_PROP_MOISTURE_DETECTED: val->intval = chg->moisture_present; break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; Loading Loading @@ -1673,6 +1684,36 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) return rc; } if (chg->uusb_moisture_protection_enabled) { /* Enable moisture detection interrupt */ 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) { dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n", rc); return rc; } /* Enable uUSB factory mode */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, EN_MICRO_USB_FACTORY_MODE_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n", rc); return rc; } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", rc); return rc; } } return rc; } Loading drivers/power/supply/qcom/smb5-lib.c +221 −3 Original line number Diff line number Diff line Loading @@ -1322,6 +1322,100 @@ int smblib_toggle_smb_en(struct smb_charger *chg, int toggle) return rc; } /**************************** * uUSB Moisture Protection * ****************************/ #define MICRO_USB_DETECTION_ON_TIME_20_MS 0x08 #define MICRO_USB_DETECTION_PERIOD_X_100 0x03 #define U_USB_STATUS_WATER_PRESENT 0x00 static int smblib_set_moisture_protection(struct smb_charger *chg, bool enable) { int rc = 0; if (chg->moisture_present == enable) { smblib_dbg(chg, PR_MISC, "No change in moisture protection status\n"); return rc; } if (enable) { chg->moisture_present = true; /* Disable uUSB factory mode detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", rc); return rc; } /* Disable moisture detection and uUSB state change interrupt */ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT | MICRO_USB_STATE_CHANGE_INT_EN_BIT, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable moisture detection interrupt rc=%d\n", rc); return rc; } /* Set 1% duty cycle on ID detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, EN_MICRO_USB_WATER_PROTECTION_BIT | MICRO_USB_DETECTION_ON_TIME_CFG_MASK | MICRO_USB_DETECTION_PERIOD_CFG_MASK, EN_MICRO_USB_WATER_PROTECTION_BIT | MICRO_USB_DETECTION_ON_TIME_20_MS | MICRO_USB_DETECTION_PERIOD_X_100); if (rc < 0) { smblib_err(chg, "Couldn't set 1 percent CC_ID duty cycle rc=%d\n", rc); return rc; } vote(chg->usb_icl_votable, MOISTURE_VOTER, true, 0); } else { chg->moisture_present = false; vote(chg->usb_icl_votable, MOISTURE_VOTER, false, 0); /* Enable moisture detection and uUSB state change interrupt */ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT | MICRO_USB_STATE_CHANGE_INT_EN_BIT, TYPEC_WATER_DETECTION_INT_EN_BIT | MICRO_USB_STATE_CHANGE_INT_EN_BIT); if (rc < 0) { smblib_err(chg, "Couldn't enable moisture detection and uUSB state change interrupt rc=%d\n", rc); return rc; } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable 1 percent CC_ID duty cycle rc=%d\n", rc); return rc; } /* Enable uUSB factory mode detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, EN_MICRO_USB_FACTORY_MODE_BIT); if (rc < 0) { smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", rc); return rc; } } smblib_dbg(chg, PR_MISC, "Moisture protection %s\n", chg->moisture_present ? "enabled" : "disabled"); return rc; } /********************* * VOTABLE CALLBACKS * *********************/ Loading Loading @@ -4749,11 +4843,27 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { if (chg->uusb_moisture_protection_enabled) { /* * Adding pm_stay_awake as because pm_relax is called * on exit path from the work routine. */ pm_stay_awake(chg->dev); schedule_work(&chg->moisture_protection_work); } cancel_delayed_work_sync(&chg->uusb_otg_work); /* * Skip OTG enablement if RID interrupt triggers with moisture * protection still enabled. */ if (!chg->moisture_present) { 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)); } goto out; } Loading Loading @@ -5301,6 +5411,96 @@ static void smblib_thermal_regulation_work(struct work_struct *work) rc); } #define MOISTURE_PROTECTION_CHECK_DELAY_MS 300000 /* 5 mins */ static void smblib_moisture_protection_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, moisture_protection_work); int rc; bool usb_plugged_in; u8 stat; /* * Disable 1% duty cycle on CC_ID pin and enable uUSB factory mode * detection to track any change on RID, as interrupts are disable. */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", rc); goto out; } rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, EN_MICRO_USB_FACTORY_MODE_BIT); if (rc < 0) { smblib_err(chg, "Couldn't enable uUSB factory mode detection rc=%d\n", rc); goto out; } /* * Add a delay of 100ms to allow change in rid to reflect on * status registers. */ msleep(100); rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); goto out; } usb_plugged_in = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); /* Check uUSB status for moisture presence */ rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_U_USB_STATUS_REG rc=%d\n", rc); goto out; } /* * Factory mode detection happens in case of USB plugged-in by using * a different current source of 2uA which can hamper moisture * detection. Since factory mode is not supported in kernel, factory * mode detection can be considered as equivalent to presence of * moisture. */ if (stat == U_USB_STATUS_WATER_PRESENT || stat == U_USB_FMB1_BIT || stat == U_USB_FMB2_BIT || (usb_plugged_in && stat == U_USB_FLOAT1_BIT)) { smblib_set_moisture_protection(chg, true); alarm_start_relative(&chg->moisture_protection_alarm, ms_to_ktime(MOISTURE_PROTECTION_CHECK_DELAY_MS)); } else { smblib_set_moisture_protection(chg, false); rc = alarm_cancel(&chg->moisture_protection_alarm); if (rc < 0) smblib_err(chg, "Couldn't cancel moisture protection alarm\n"); } out: pm_relax(chg->dev); } static enum alarmtimer_restart moisture_protection_alarm_cb(struct alarm *alarm, ktime_t now) { struct smb_charger *chg = container_of(alarm, struct smb_charger, moisture_protection_alarm); smblib_dbg(chg, PR_MISC, "moisture Protection Alarm Triggered %lld\n", ktime_to_ms(now)); /* Atomic context, cannot use voter */ pm_stay_awake(chg->dev); schedule_work(&chg->moisture_protection_work); return ALARMTIMER_NORESTART; } static void jeita_update_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, Loading Loading @@ -5689,6 +5889,20 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->lpd_detach_work, smblib_lpd_detach_work); INIT_DELAYED_WORK(&chg->thermal_regulation_work, smblib_thermal_regulation_work); if (chg->uusb_moisture_protection_enabled) { INIT_WORK(&chg->moisture_protection_work, smblib_moisture_protection_work); if (alarmtimer_get_rtcdev()) { alarm_init(&chg->moisture_protection_alarm, ALARM_BOOTTIME, moisture_protection_alarm_cb); } else { smblib_err(chg, "Failed to initialize moisture protection alarm\n"); return -ENODEV; } } chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; Loading Loading @@ -5781,6 +5995,10 @@ int smblib_deinit(struct smb_charger *chg) { switch (chg->mode) { case PARALLEL_MASTER: if (chg->uusb_moisture_protection_enabled) { alarm_cancel(&chg->moisture_protection_alarm); cancel_work_sync(&chg->moisture_protection_work); } cancel_work_sync(&chg->bms_update_work); cancel_work_sync(&chg->jeita_update_work); cancel_work_sync(&chg->pl_update_work); Loading drivers/power/supply/qcom/smb5-lib.h +5 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ enum print_reason { #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" #define SW_THERM_REGULATION_VOTER "SW_THERM_REGULATION_VOTER" #define JEITA_ARB_VOTER "JEITA_ARB_VOTER" #define MOISTURE_VOTER "MOISTURE_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 Loading Loading @@ -378,6 +379,7 @@ struct smb_charger { struct work_struct bms_update_work; struct work_struct pl_update_work; struct work_struct jeita_update_work; struct work_struct moisture_protection_work; struct delayed_work ps_change_timeout_work; struct delayed_work clear_hdc_work; struct delayed_work icl_change_work; Loading @@ -389,6 +391,7 @@ struct smb_charger { struct delayed_work thermal_regulation_work; struct alarm lpd_recheck_timer; struct alarm moisture_protection_alarm; /* secondary charger config */ bool sec_pl_present; Loading Loading @@ -455,6 +458,8 @@ struct smb_charger { u32 jeita_soft_hys_thlds[2]; int jeita_soft_fcc[2]; int jeita_soft_fv[2]; bool moisture_present; bool uusb_moisture_protection_enabled; /* workaround flag */ u32 wa_flags; Loading drivers/power/supply/qcom/smb5-reg.h +11 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ enum { #define USBIN_SUSPEND_STS_BIT BIT(6) #define USE_USBIN_BIT BIT(4) #define USE_DCIN_BIT BIT(3) #define POWER_PATH_MASK GENMASK(2, 1) #define VALID_INPUT_POWER_SOURCE_STS_BIT BIT(0) #define DCDC_CMD_OTG_REG (DCDC_BASE + 0x40) Loading Loading @@ -341,6 +342,10 @@ enum { #define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F) #define U_USB_GROUND_NOVBUS_BIT BIT(6) #define U_USB_GROUND_BIT BIT(4) #define U_USB_FMB1_BIT BIT(3) #define U_USB_FLOAT1_BIT BIT(2) #define U_USB_FMB2_BIT BIT(1) #define U_USB_FLOAT2_BIT BIT(0) #define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44) #define TYPEC_TRY_MODE_MASK GENMASK(4, 3) Loading Loading @@ -409,8 +414,14 @@ enum { #define SEL_SBU2_ISRC_VAL 0x01 #define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70) #define EN_MICRO_USB_FACTORY_MODE_BIT BIT(1) #define EN_MICRO_USB_MODE_BIT BIT(0) #define TYPEC_U_USB_WATER_PROTECTION_CFG_REG (TYPEC_BASE + 0x73) #define EN_MICRO_USB_WATER_PROTECTION_BIT BIT(4) #define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) #define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) #define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x73) #define MICRO_USB_MODE_ONLY_BIT BIT(0) /******************************** Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,12 @@ Charger specific properties: Definition: Boolean flag which when present disables suspend on collapse feature of charger hardware. - qcom,uusb-moisture-protection-enable Usage: optional Value type: bool Definition: Boolean flag which when present enables mositure protection feature for uUSB connector type. ============================================= Second Level Nodes - SMB5 Charger Peripherals ============================================= Loading
drivers/power/supply/qcom/qpnp-smb5.c +41 −0 Original line number Diff line number Diff line Loading @@ -258,6 +258,8 @@ static int smb5_chg_config_init(struct smb5 *chip) chg->param = smb5_pm8150b_params; chg->name = "pm6150_charger"; chg->wa_flags |= SW_THERM_REGULATION_WA; if (pmic_rev_id->rev4 >= 2) chg->uusb_moisture_protection_enabled = true; chg->main_fcc_max = PM6150_MAX_FCC_UA; break; case PMI632_SUBTYPE: Loading Loading @@ -444,6 +446,11 @@ static int smb5_parse_dt(struct smb5 *chip) chg->fcc_stepper_enable = of_property_read_bool(node, "qcom,fcc-stepping-enable"); chg->uusb_moisture_protection_enabled = chg->uusb_moisture_protection_enabled && of_property_read_bool(node, "qcom,uusb-moisture-protection-enable"); /* Extract ADC channels */ rc = smblib_get_iio_channel(chg, "mid_voltage", &chg->iio.mid_chan); if (rc < 0) Loading Loading @@ -530,6 +537,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_SMB_EN_MODE, POWER_SUPPLY_PROP_SMB_EN_REASON, POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_MOISTURE_DETECTED, }; static int smb5_usb_get_prop(struct power_supply *psy, Loading Loading @@ -671,6 +679,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_SMB_EN_REASON: val->intval = chg->cp_reason; break; case POWER_SUPPLY_PROP_MOISTURE_DETECTED: val->intval = chg->moisture_present; break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; Loading Loading @@ -1673,6 +1684,36 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) return rc; } if (chg->uusb_moisture_protection_enabled) { /* Enable moisture detection interrupt */ 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) { dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n", rc); return rc; } /* Enable uUSB factory mode */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, EN_MICRO_USB_FACTORY_MODE_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n", rc); return rc; } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", rc); return rc; } } return rc; } Loading
drivers/power/supply/qcom/smb5-lib.c +221 −3 Original line number Diff line number Diff line Loading @@ -1322,6 +1322,100 @@ int smblib_toggle_smb_en(struct smb_charger *chg, int toggle) return rc; } /**************************** * uUSB Moisture Protection * ****************************/ #define MICRO_USB_DETECTION_ON_TIME_20_MS 0x08 #define MICRO_USB_DETECTION_PERIOD_X_100 0x03 #define U_USB_STATUS_WATER_PRESENT 0x00 static int smblib_set_moisture_protection(struct smb_charger *chg, bool enable) { int rc = 0; if (chg->moisture_present == enable) { smblib_dbg(chg, PR_MISC, "No change in moisture protection status\n"); return rc; } if (enable) { chg->moisture_present = true; /* Disable uUSB factory mode detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", rc); return rc; } /* Disable moisture detection and uUSB state change interrupt */ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT | MICRO_USB_STATE_CHANGE_INT_EN_BIT, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable moisture detection interrupt rc=%d\n", rc); return rc; } /* Set 1% duty cycle on ID detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, EN_MICRO_USB_WATER_PROTECTION_BIT | MICRO_USB_DETECTION_ON_TIME_CFG_MASK | MICRO_USB_DETECTION_PERIOD_CFG_MASK, EN_MICRO_USB_WATER_PROTECTION_BIT | MICRO_USB_DETECTION_ON_TIME_20_MS | MICRO_USB_DETECTION_PERIOD_X_100); if (rc < 0) { smblib_err(chg, "Couldn't set 1 percent CC_ID duty cycle rc=%d\n", rc); return rc; } vote(chg->usb_icl_votable, MOISTURE_VOTER, true, 0); } else { chg->moisture_present = false; vote(chg->usb_icl_votable, MOISTURE_VOTER, false, 0); /* Enable moisture detection and uUSB state change interrupt */ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT | MICRO_USB_STATE_CHANGE_INT_EN_BIT, TYPEC_WATER_DETECTION_INT_EN_BIT | MICRO_USB_STATE_CHANGE_INT_EN_BIT); if (rc < 0) { smblib_err(chg, "Couldn't enable moisture detection and uUSB state change interrupt rc=%d\n", rc); return rc; } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable 1 percent CC_ID duty cycle rc=%d\n", rc); return rc; } /* Enable uUSB factory mode detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, EN_MICRO_USB_FACTORY_MODE_BIT); if (rc < 0) { smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", rc); return rc; } } smblib_dbg(chg, PR_MISC, "Moisture protection %s\n", chg->moisture_present ? "enabled" : "disabled"); return rc; } /********************* * VOTABLE CALLBACKS * *********************/ Loading Loading @@ -4749,11 +4843,27 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { if (chg->uusb_moisture_protection_enabled) { /* * Adding pm_stay_awake as because pm_relax is called * on exit path from the work routine. */ pm_stay_awake(chg->dev); schedule_work(&chg->moisture_protection_work); } cancel_delayed_work_sync(&chg->uusb_otg_work); /* * Skip OTG enablement if RID interrupt triggers with moisture * protection still enabled. */ if (!chg->moisture_present) { 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)); } goto out; } Loading Loading @@ -5301,6 +5411,96 @@ static void smblib_thermal_regulation_work(struct work_struct *work) rc); } #define MOISTURE_PROTECTION_CHECK_DELAY_MS 300000 /* 5 mins */ static void smblib_moisture_protection_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, moisture_protection_work); int rc; bool usb_plugged_in; u8 stat; /* * Disable 1% duty cycle on CC_ID pin and enable uUSB factory mode * detection to track any change on RID, as interrupts are disable. */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", rc); goto out; } rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, EN_MICRO_USB_FACTORY_MODE_BIT, EN_MICRO_USB_FACTORY_MODE_BIT); if (rc < 0) { smblib_err(chg, "Couldn't enable uUSB factory mode detection rc=%d\n", rc); goto out; } /* * Add a delay of 100ms to allow change in rid to reflect on * status registers. */ msleep(100); rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); goto out; } usb_plugged_in = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); /* Check uUSB status for moisture presence */ rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_U_USB_STATUS_REG rc=%d\n", rc); goto out; } /* * Factory mode detection happens in case of USB plugged-in by using * a different current source of 2uA which can hamper moisture * detection. Since factory mode is not supported in kernel, factory * mode detection can be considered as equivalent to presence of * moisture. */ if (stat == U_USB_STATUS_WATER_PRESENT || stat == U_USB_FMB1_BIT || stat == U_USB_FMB2_BIT || (usb_plugged_in && stat == U_USB_FLOAT1_BIT)) { smblib_set_moisture_protection(chg, true); alarm_start_relative(&chg->moisture_protection_alarm, ms_to_ktime(MOISTURE_PROTECTION_CHECK_DELAY_MS)); } else { smblib_set_moisture_protection(chg, false); rc = alarm_cancel(&chg->moisture_protection_alarm); if (rc < 0) smblib_err(chg, "Couldn't cancel moisture protection alarm\n"); } out: pm_relax(chg->dev); } static enum alarmtimer_restart moisture_protection_alarm_cb(struct alarm *alarm, ktime_t now) { struct smb_charger *chg = container_of(alarm, struct smb_charger, moisture_protection_alarm); smblib_dbg(chg, PR_MISC, "moisture Protection Alarm Triggered %lld\n", ktime_to_ms(now)); /* Atomic context, cannot use voter */ pm_stay_awake(chg->dev); schedule_work(&chg->moisture_protection_work); return ALARMTIMER_NORESTART; } static void jeita_update_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, Loading Loading @@ -5689,6 +5889,20 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->lpd_detach_work, smblib_lpd_detach_work); INIT_DELAYED_WORK(&chg->thermal_regulation_work, smblib_thermal_regulation_work); if (chg->uusb_moisture_protection_enabled) { INIT_WORK(&chg->moisture_protection_work, smblib_moisture_protection_work); if (alarmtimer_get_rtcdev()) { alarm_init(&chg->moisture_protection_alarm, ALARM_BOOTTIME, moisture_protection_alarm_cb); } else { smblib_err(chg, "Failed to initialize moisture protection alarm\n"); return -ENODEV; } } chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; Loading Loading @@ -5781,6 +5995,10 @@ int smblib_deinit(struct smb_charger *chg) { switch (chg->mode) { case PARALLEL_MASTER: if (chg->uusb_moisture_protection_enabled) { alarm_cancel(&chg->moisture_protection_alarm); cancel_work_sync(&chg->moisture_protection_work); } cancel_work_sync(&chg->bms_update_work); cancel_work_sync(&chg->jeita_update_work); cancel_work_sync(&chg->pl_update_work); Loading
drivers/power/supply/qcom/smb5-lib.h +5 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ enum print_reason { #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" #define SW_THERM_REGULATION_VOTER "SW_THERM_REGULATION_VOTER" #define JEITA_ARB_VOTER "JEITA_ARB_VOTER" #define MOISTURE_VOTER "MOISTURE_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 Loading Loading @@ -378,6 +379,7 @@ struct smb_charger { struct work_struct bms_update_work; struct work_struct pl_update_work; struct work_struct jeita_update_work; struct work_struct moisture_protection_work; struct delayed_work ps_change_timeout_work; struct delayed_work clear_hdc_work; struct delayed_work icl_change_work; Loading @@ -389,6 +391,7 @@ struct smb_charger { struct delayed_work thermal_regulation_work; struct alarm lpd_recheck_timer; struct alarm moisture_protection_alarm; /* secondary charger config */ bool sec_pl_present; Loading Loading @@ -455,6 +458,8 @@ struct smb_charger { u32 jeita_soft_hys_thlds[2]; int jeita_soft_fcc[2]; int jeita_soft_fv[2]; bool moisture_present; bool uusb_moisture_protection_enabled; /* workaround flag */ u32 wa_flags; Loading
drivers/power/supply/qcom/smb5-reg.h +11 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ enum { #define USBIN_SUSPEND_STS_BIT BIT(6) #define USE_USBIN_BIT BIT(4) #define USE_DCIN_BIT BIT(3) #define POWER_PATH_MASK GENMASK(2, 1) #define VALID_INPUT_POWER_SOURCE_STS_BIT BIT(0) #define DCDC_CMD_OTG_REG (DCDC_BASE + 0x40) Loading Loading @@ -341,6 +342,10 @@ enum { #define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F) #define U_USB_GROUND_NOVBUS_BIT BIT(6) #define U_USB_GROUND_BIT BIT(4) #define U_USB_FMB1_BIT BIT(3) #define U_USB_FLOAT1_BIT BIT(2) #define U_USB_FMB2_BIT BIT(1) #define U_USB_FLOAT2_BIT BIT(0) #define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44) #define TYPEC_TRY_MODE_MASK GENMASK(4, 3) Loading Loading @@ -409,8 +414,14 @@ enum { #define SEL_SBU2_ISRC_VAL 0x01 #define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70) #define EN_MICRO_USB_FACTORY_MODE_BIT BIT(1) #define EN_MICRO_USB_MODE_BIT BIT(0) #define TYPEC_U_USB_WATER_PROTECTION_CFG_REG (TYPEC_BASE + 0x73) #define EN_MICRO_USB_WATER_PROTECTION_BIT BIT(4) #define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) #define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) #define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x73) #define MICRO_USB_MODE_ONLY_BIT BIT(0) /******************************** Loading