Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -280,6 +280,12 @@ Charger specific properties: Value type: bool Definition: Boolean flag which when present disables USB-PD operation. - qcom,lpd-disable Usage: optional Value type: bool Definition: Boolean flag which when present disables liquid presence detection. - qcom,hw-die-temp-mitigation Usage: optional Value type: bool Loading drivers/power/supply/qcom/qpnp-smb5.c +211 −148 Original line number Diff line number Diff line Loading @@ -340,6 +340,9 @@ static int smb5_chg_config_init(struct smb5 *chip) chg->name = "pmi632_charger"; /* PMI632 does not support PD */ chg->pd_not_supported = true; chg->lpd_disabled = true; if (pmic_rev_id->rev4 >= 2) chg->uusb_moisture_protection_enabled = true; chg->hw_max_icl_ua = (chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua : PMI632_MAX_ICL_UA; Loading Loading @@ -436,6 +439,8 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) chg->pd_not_supported = of_property_read_bool(node, "qcom,usb-pd-disable"); chg->lpd_disabled = of_property_read_bool(node, "qcom,lpd-disable"); rc = of_property_read_u32(node, "qcom,wd-bark-time-secs", &chip->dt.wd_bark_time); if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME) Loading Loading @@ -1831,10 +1836,10 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } val = chg->lpd_disabled ? 0 : TYPEC_WATER_DETECTION_INT_EN_BIT; /* Use simple write to enable only required interrupts */ rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_SRC_BATT_HPWR_INT_EN_BIT | TYPEC_WATER_DETECTION_INT_EN_BIT); TYPEC_SRC_BATT_HPWR_INT_EN_BIT | val); if (rc < 0) { dev_err(chg->dev, "Couldn't configure Type-C interrupts rc=%d\n", rc); Loading Loading @@ -1926,7 +1931,9 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); rc = smblib_write(chg, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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); Loading Loading @@ -2090,12 +2097,189 @@ static int smb5_init_dc_peripheral(struct smb_charger *chg) return rc; } static int smb5_init_hw(struct smb5 *chip) static int smb5_configure_recharging(struct smb5 *chip) { int rc = 0; struct smb_charger *chg = &chip->chg; union power_supply_propval pval; /* Configure VBATT-based or automatic recharging */ rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_vbat_mv != -EINVAL) ? VBAT_BASED_RECHG_BIT : 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge VBAT threshold */ if (chip->dt.auto_recharge_vbat_mv != -EINVAL) { u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv); temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8); rc = smblib_batch_write(chg, CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2); if (rc < 0) { dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n", rc); return rc; } /* Program the sample count for VBAT based recharge to 3 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); return rc; } } rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_soc != -EINVAL) ? SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge threshold */ if (chip->dt.auto_recharge_soc != -EINVAL) { pval.intval = chip->dt.auto_recharge_soc; rc = smblib_set_prop_rechg_soc_thresh(chg, &pval); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n", rc); return rc; } /* Program the sample count for SOC based recharge to 1 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); return rc; } } return 0; } static int smb5_configure_float_charger(struct smb5 *chip) { int rc = 0; struct smb_charger *chg = &chip->chg; /* configure float charger options */ switch (chip->dt.float_option) { case FLOAT_DCP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, 0); break; case FLOAT_SDP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT); break; case DISABLE_CHARGING: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT); break; case SUSPEND_INPUT: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT); break; default: rc = 0; break; } if (rc < 0) { dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n", rc); return rc; } rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg); if (rc < 0) { dev_err(chg->dev, "Couldn't read float charger options rc=%d\n", rc); return rc; } return 0; } static int smb5_init_connector_type(struct smb_charger *chg) { int rc, type = 0; u8 val = 0; /* * PMI632 can have the connector type defined by a dedicated register * PMI632_TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG. */ if (chg->smb_version == PMI632_SUBTYPE) { rc = smblib_read(chg, PMI632_TYPEC_MICRO_USB_MODE_REG, &val); if (rc < 0) { dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc); return rc; } type = !!(val & MICRO_USB_MODE_ONLY_BIT); } /* * If PMI632_TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632 * check the connector type using TYPEC_U_USB_CFG_REG. */ if (!type) { rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val); if (rc < 0) { dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n", rc); return rc; } type = !!(val & EN_MICRO_USB_MODE_BIT); } pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC"); if (type) { chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; 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: * - Rerun APSD to ensure proper charger detection if device * boots with charger connected. * - Initialize flash module for PMI632 */ if (chg->smb_version == PMI632_SUBTYPE) { schgm_flash_init(chg); smblib_rerun_apsd_if_required(chg); } return 0; } static int smb5_init_hw(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; int rc; u8 val = 0, mask = 0; union power_supply_propval pval; if (chip->dt.no_battery) chg->fake_capacity = 50; Loading Loading @@ -2170,60 +2354,13 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } /* * PMI632 can have the connector type defined by a dedicated register * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG. */ if (chg->smb_version == PMI632_SUBTYPE) { rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val); rc = smb5_init_connector_type(chg); if (rc < 0) { dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc); return rc; } type = !!(val & MICRO_USB_MODE_ONLY_BIT); } /* * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632 * check the connector type using TYPEC_U_USB_CFG_REG. */ if (!type) { rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val); if (rc < 0) { dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n", dev_err(chg->dev, "Couldn't configure connector type rc=%d\n", rc); return rc; } type = !!(val & EN_MICRO_USB_MODE_BIT); } pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC"); if (type) { chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; 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: * - Rerun APSD to ensure proper charger detection if device * boots with charger connected. * - Initialize flash module for PMI632 */ if (chg->smb_version == PMI632_SUBTYPE) { schgm_flash_init(chg); smblib_rerun_apsd_if_required(chg); } /* Use ICL results from HW */ rc = smblib_icl_override(chg, HW_AUTO_MODE); if (rc < 0) { Loading Loading @@ -2337,41 +2474,9 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } /* configure float charger options */ switch (chip->dt.float_option) { case FLOAT_DCP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, 0); break; case FLOAT_SDP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT); break; case DISABLE_CHARGING: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT); break; case SUSPEND_INPUT: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT); break; default: rc = 0; break; } if (rc < 0) { dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n", rc); return rc; } rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg); if (rc < 0) { dev_err(chg->dev, "Couldn't read float charger options rc=%d\n", rc); rc = smb5_configure_float_charger(chip); if (rc < 0) return rc; } switch (chip->dt.chg_inhibit_thr_mv) { case 50: Loading Loading @@ -2415,66 +2520,9 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_vbat_mv != -EINVAL) ? VBAT_BASED_RECHG_BIT : 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge VBAT threshold */ if (chip->dt.auto_recharge_vbat_mv != -EINVAL) { u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv); temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8); rc = smblib_batch_write(chg, CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2); if (rc < 0) { dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n", rc); return rc; } /* Program the sample count for VBAT based recharge to 3 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); return rc; } } rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_soc != -EINVAL) ? SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge threshold */ if (chip->dt.auto_recharge_soc != -EINVAL) { pval.intval = chip->dt.auto_recharge_soc; rc = smblib_set_prop_rechg_soc_thresh(chg, &pval); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n", rc); return rc; } /* Program the sample count for SOC based recharge to 1 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); rc = smb5_configure_recharging(chip); if (rc < 0) return rc; } } rc = smblib_disable_hw_jeita(chg, true); if (rc < 0) { Loading Loading @@ -3129,6 +3177,21 @@ static int smb5_probe(struct platform_device *pdev) goto cleanup; } /* Support reporting polarity and speed via properties */ rc = extcon_set_property_capability(chg->extcon, EXTCON_USB, EXTCON_PROP_USB_TYPEC_POLARITY); rc |= extcon_set_property_capability(chg->extcon, EXTCON_USB, EXTCON_PROP_USB_SS); rc |= extcon_set_property_capability(chg->extcon, EXTCON_USB_HOST, EXTCON_PROP_USB_TYPEC_POLARITY); rc |= extcon_set_property_capability(chg->extcon, EXTCON_USB_HOST, EXTCON_PROP_USB_SS); if (rc < 0) { dev_err(chg->dev, "failed to configure extcon capabilities\n"); goto cleanup; } rc = smb5_init_hw(chip); if (rc < 0) { pr_err("Couldn't initialize hardware rc=%d\n", rc); Loading drivers/power/supply/qcom/smb1355-charger.c +14 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,9 @@ #define BATT_GT_PRE_TO_FAST_BIT BIT(4) #define ENABLE_CHARGING_BIT BIT(3) #define CHGR_CHARGING_ENABLE_CMD_REG (CHGR_BASE + 0x42) #define CHARGING_ENABLE_CMD_BIT BIT(0) #define CHGR_CFG2_REG (CHGR_BASE + 0x51) #define CHG_EN_SRC_BIT BIT(7) #define CHG_EN_POLARITY_BIT BIT(6) Loading Loading @@ -1032,7 +1035,17 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } /* disable parallel charging path */ /* * Disable command based SMB1355 enablement and disable parallel * charging path by switching to command based mode. */ rc = smb1355_masked_write(chip, CHGR_CHARGING_ENABLE_CMD_REG, CHARGING_ENABLE_CMD_BIT, 0); if (rc < 0) { pr_err("Coudln't configure command bit, rc=%d\n", rc); return rc; } rc = smb1355_set_parallel_charging(chip, true); if (rc < 0) { pr_err("Couldn't disable parallel path rc=%d\n", rc); Loading drivers/power/supply/qcom/smb1390-charger-psy.c +52 −34 Original line number Diff line number Diff line Loading @@ -124,7 +124,6 @@ struct smb1390 { struct votable *ilim_votable; struct votable *fcc_votable; struct votable *fv_votable; struct votable *cp_awake_votable; /* power supplies */ struct power_supply *usb_psy; Loading @@ -138,7 +137,9 @@ struct smb1390 { struct smb1390_iio iio; int irq_status; int taper_entry_fv; bool switcher_disabled; bool switcher_enabled; int die_temp; bool suspended; }; struct smb_irq { Loading Loading @@ -276,8 +277,8 @@ static irqreturn_t default_irq_handler(int irq, void *data) rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, &enable); if (!rc) { if (chip->switcher_disabled == enable) { chip->switcher_disabled = !chip->switcher_disabled; if (chip->switcher_enabled != enable) { chip->switcher_enabled = enable; if (chip->fcc_votable) rerun_election(chip->fcc_votable); } Loading Loading @@ -424,7 +425,7 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, struct smb1390 *chip = data; int rc = 0; if (!is_psy_voter_available(chip)) if (!is_psy_voter_available(chip) || chip->suspended) return -EAGAIN; if (disable) { Loading @@ -432,10 +433,7 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, CMD_EN_SWITCHER_BIT, 0); if (rc < 0) return rc; vote(chip->cp_awake_votable, CP_VOTER, false, 0); } else { vote(chip->cp_awake_votable, CP_VOTER, true, 0); rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); if (rc < 0) Loading @@ -454,7 +452,7 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, struct smb1390 *chip = data; int rc = 0; if (!is_psy_voter_available(chip)) if (!is_psy_voter_available(chip) || chip->suspended) return -EAGAIN; /* ILIM should always have at least one active vote */ Loading Loading @@ -483,20 +481,6 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, return rc; } static int smb1390_awake_vote_cb(struct votable *votable, void *data, int awake, const char *client) { struct smb1390 *chip = data; if (awake) __pm_stay_awake(chip->cp_ws); else __pm_relax(chip->cp_ws); pr_debug("client: %s awake: %d\n", client, awake); return 0; } static int smb1390_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { Loading Loading @@ -705,12 +689,26 @@ static int smb1390_get_prop(struct power_supply *psy, !get_effective_result(chip->disable_votable); break; case POWER_SUPPLY_PROP_CP_SWITCHER_EN: rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, &enable); if (chip->suspended) { val->intval = chip->switcher_enabled; } else { rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, &enable); if (!rc) val->intval = enable; } break; case POWER_SUPPLY_PROP_CP_DIE_TEMP: if (chip->suspended) { if (chip->die_temp != -ENODATA) val->intval = chip->die_temp; else rc = -ENODATA; } else { rc = smb1390_get_die_temp(chip, val); if (rc >= 0) chip->die_temp = val->intval; } break; case POWER_SUPPLY_PROP_CP_ISNS: rc = smb1390_get_isns(chip, val); Loading Loading @@ -844,11 +842,6 @@ static void smb1390_release_channels(struct smb1390 *chip) static int smb1390_create_votables(struct smb1390 *chip) { chip->cp_awake_votable = create_votable("CP_AWAKE", VOTE_SET_ANY, smb1390_awake_vote_cb, chip); if (IS_ERR(chip->cp_awake_votable)) return PTR_ERR(chip->cp_awake_votable); chip->disable_votable = create_votable("CP_DISABLE", VOTE_SET_ANY, smb1390_disable_vote_cb, chip); if (IS_ERR(chip->disable_votable)) Loading Loading @@ -880,7 +873,6 @@ static void smb1390_destroy_votables(struct smb1390 *chip) { destroy_votable(chip->disable_votable); destroy_votable(chip->ilim_votable); destroy_votable(chip->cp_awake_votable); } static int smb1390_init_hw(struct smb1390 *chip) Loading Loading @@ -989,7 +981,8 @@ static int smb1390_probe(struct platform_device *pdev) chip->dev = &pdev->dev; spin_lock_init(&chip->status_change_lock); mutex_init(&chip->die_chan_lock); chip->switcher_disabled = true; chip->die_temp = -ENODATA; platform_set_drvdata(pdev, chip); chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { Loading Loading @@ -1071,6 +1064,30 @@ static int smb1390_remove(struct platform_device *pdev) return 0; } static int smb1390_suspend(struct device *dev) { struct smb1390 *chip = dev_get_drvdata(dev); chip->suspended = true; return 0; } static int smb1390_resume(struct device *dev) { struct smb1390 *chip = dev_get_drvdata(dev); chip->suspended = false; rerun_election(chip->ilim_votable); rerun_election(chip->disable_votable); return 0; } static const struct dev_pm_ops smb1390_pm_ops = { .suspend = smb1390_suspend, .resume = smb1390_resume, }; static const struct of_device_id match_table[] = { { .compatible = "qcom,smb1390-charger-psy", }, { }, Loading @@ -1079,6 +1096,7 @@ static const struct of_device_id match_table[] = { static struct platform_driver smb1390_driver = { .driver = { .name = "qcom,smb1390-charger-psy", .pm = &smb1390_pm_ops, .of_match_table = match_table, }, .probe = smb1390_probe, Loading drivers/power/supply/qcom/smb5-lib.c +66 −30 Original line number Diff line number Diff line Loading @@ -1423,7 +1423,9 @@ static int smblib_set_moisture_protection(struct smb_charger *chg, /* Set 1% duty cycle on ID detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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, Loading Loading @@ -1454,7 +1456,9 @@ static int smblib_set_moisture_protection(struct smb_charger *chg, } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); rc = smblib_write(chg, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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); Loading Loading @@ -2730,6 +2734,11 @@ int smblib_get_prop_dc_present(struct smb_charger *chg, int rc; u8 stat; if (chg->smb_version == PMI632_SUBTYPE) { val->intval = 0; return 0; } rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc); Loading @@ -2746,6 +2755,11 @@ int smblib_get_prop_dc_online(struct smb_charger *chg, int rc = 0; u8 stat; if (chg->smb_version == PMI632_SUBTYPE) { val->intval = 0; return 0; } if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) { val->intval = false; return rc; Loading Loading @@ -4897,6 +4911,9 @@ static bool smblib_src_lpd(struct smb_charger *chg) u8 stat; int rc; if (chg->lpd_disabled) return false; 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 @@ -5139,12 +5156,35 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) chg->typec_mode, typec_mode); } static void smblib_lpd_launch_ra_open_work(struct smb_charger *chg) { u8 stat; int rc; if (chg->lpd_disabled) return; 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; } if (!(stat & TYPEC_TCCDEBOUNCE_DONE_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)); } } 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); Loading Loading @@ -5176,21 +5216,7 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) if (chg->pr_swap_in_progress || chg->pd_hard_reset) 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; } if (!(stat & TYPEC_TCCDEBOUNCE_DONE_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)); } smblib_lpd_launch_ra_open_work(chg); if (chg->usb_psy) power_supply_changed(chg->usb_psy); Loading Loading @@ -5225,6 +5251,16 @@ irqreturn_t typec_state_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } static void smblib_lpd_clear_ra_open_work(struct smb_charger *chg) { if (chg->lpd_disabled) return; cancel_delayed_work_sync(&chg->lpd_detach_work); chg->lpd_stage = LPD_STAGE_FLOAT_CANCEL; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, false, 0); } irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) { Loading @@ -5243,10 +5279,8 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) } if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) { cancel_delayed_work_sync(&chg->lpd_detach_work); chg->lpd_stage = LPD_STAGE_FLOAT_CANCEL; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, false, 0); smblib_lpd_clear_ra_open_work(chg); rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { Loading Loading @@ -5782,7 +5816,9 @@ static void smblib_moisture_protection_work(struct work_struct *work) * 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); rc = smblib_write(chg, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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); Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -280,6 +280,12 @@ Charger specific properties: Value type: bool Definition: Boolean flag which when present disables USB-PD operation. - qcom,lpd-disable Usage: optional Value type: bool Definition: Boolean flag which when present disables liquid presence detection. - qcom,hw-die-temp-mitigation Usage: optional Value type: bool Loading
drivers/power/supply/qcom/qpnp-smb5.c +211 −148 Original line number Diff line number Diff line Loading @@ -340,6 +340,9 @@ static int smb5_chg_config_init(struct smb5 *chip) chg->name = "pmi632_charger"; /* PMI632 does not support PD */ chg->pd_not_supported = true; chg->lpd_disabled = true; if (pmic_rev_id->rev4 >= 2) chg->uusb_moisture_protection_enabled = true; chg->hw_max_icl_ua = (chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua : PMI632_MAX_ICL_UA; Loading Loading @@ -436,6 +439,8 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) chg->pd_not_supported = of_property_read_bool(node, "qcom,usb-pd-disable"); chg->lpd_disabled = of_property_read_bool(node, "qcom,lpd-disable"); rc = of_property_read_u32(node, "qcom,wd-bark-time-secs", &chip->dt.wd_bark_time); if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME) Loading Loading @@ -1831,10 +1836,10 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } val = chg->lpd_disabled ? 0 : TYPEC_WATER_DETECTION_INT_EN_BIT; /* Use simple write to enable only required interrupts */ rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_SRC_BATT_HPWR_INT_EN_BIT | TYPEC_WATER_DETECTION_INT_EN_BIT); TYPEC_SRC_BATT_HPWR_INT_EN_BIT | val); if (rc < 0) { dev_err(chg->dev, "Couldn't configure Type-C interrupts rc=%d\n", rc); Loading Loading @@ -1926,7 +1931,9 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); rc = smblib_write(chg, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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); Loading Loading @@ -2090,12 +2097,189 @@ static int smb5_init_dc_peripheral(struct smb_charger *chg) return rc; } static int smb5_init_hw(struct smb5 *chip) static int smb5_configure_recharging(struct smb5 *chip) { int rc = 0; struct smb_charger *chg = &chip->chg; union power_supply_propval pval; /* Configure VBATT-based or automatic recharging */ rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_vbat_mv != -EINVAL) ? VBAT_BASED_RECHG_BIT : 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge VBAT threshold */ if (chip->dt.auto_recharge_vbat_mv != -EINVAL) { u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv); temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8); rc = smblib_batch_write(chg, CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2); if (rc < 0) { dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n", rc); return rc; } /* Program the sample count for VBAT based recharge to 3 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); return rc; } } rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_soc != -EINVAL) ? SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge threshold */ if (chip->dt.auto_recharge_soc != -EINVAL) { pval.intval = chip->dt.auto_recharge_soc; rc = smblib_set_prop_rechg_soc_thresh(chg, &pval); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n", rc); return rc; } /* Program the sample count for SOC based recharge to 1 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); return rc; } } return 0; } static int smb5_configure_float_charger(struct smb5 *chip) { int rc = 0; struct smb_charger *chg = &chip->chg; /* configure float charger options */ switch (chip->dt.float_option) { case FLOAT_DCP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, 0); break; case FLOAT_SDP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT); break; case DISABLE_CHARGING: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT); break; case SUSPEND_INPUT: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT); break; default: rc = 0; break; } if (rc < 0) { dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n", rc); return rc; } rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg); if (rc < 0) { dev_err(chg->dev, "Couldn't read float charger options rc=%d\n", rc); return rc; } return 0; } static int smb5_init_connector_type(struct smb_charger *chg) { int rc, type = 0; u8 val = 0; /* * PMI632 can have the connector type defined by a dedicated register * PMI632_TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG. */ if (chg->smb_version == PMI632_SUBTYPE) { rc = smblib_read(chg, PMI632_TYPEC_MICRO_USB_MODE_REG, &val); if (rc < 0) { dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc); return rc; } type = !!(val & MICRO_USB_MODE_ONLY_BIT); } /* * If PMI632_TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632 * check the connector type using TYPEC_U_USB_CFG_REG. */ if (!type) { rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val); if (rc < 0) { dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n", rc); return rc; } type = !!(val & EN_MICRO_USB_MODE_BIT); } pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC"); if (type) { chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; 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: * - Rerun APSD to ensure proper charger detection if device * boots with charger connected. * - Initialize flash module for PMI632 */ if (chg->smb_version == PMI632_SUBTYPE) { schgm_flash_init(chg); smblib_rerun_apsd_if_required(chg); } return 0; } static int smb5_init_hw(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; int rc; u8 val = 0, mask = 0; union power_supply_propval pval; if (chip->dt.no_battery) chg->fake_capacity = 50; Loading Loading @@ -2170,60 +2354,13 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } /* * PMI632 can have the connector type defined by a dedicated register * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG. */ if (chg->smb_version == PMI632_SUBTYPE) { rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val); rc = smb5_init_connector_type(chg); if (rc < 0) { dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc); return rc; } type = !!(val & MICRO_USB_MODE_ONLY_BIT); } /* * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632 * check the connector type using TYPEC_U_USB_CFG_REG. */ if (!type) { rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val); if (rc < 0) { dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n", dev_err(chg->dev, "Couldn't configure connector type rc=%d\n", rc); return rc; } type = !!(val & EN_MICRO_USB_MODE_BIT); } pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC"); if (type) { chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; 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: * - Rerun APSD to ensure proper charger detection if device * boots with charger connected. * - Initialize flash module for PMI632 */ if (chg->smb_version == PMI632_SUBTYPE) { schgm_flash_init(chg); smblib_rerun_apsd_if_required(chg); } /* Use ICL results from HW */ rc = smblib_icl_override(chg, HW_AUTO_MODE); if (rc < 0) { Loading Loading @@ -2337,41 +2474,9 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } /* configure float charger options */ switch (chip->dt.float_option) { case FLOAT_DCP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, 0); break; case FLOAT_SDP: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT); break; case DISABLE_CHARGING: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT); break; case SUSPEND_INPUT: rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT); break; default: rc = 0; break; } if (rc < 0) { dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n", rc); return rc; } rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg); if (rc < 0) { dev_err(chg->dev, "Couldn't read float charger options rc=%d\n", rc); rc = smb5_configure_float_charger(chip); if (rc < 0) return rc; } switch (chip->dt.chg_inhibit_thr_mv) { case 50: Loading Loading @@ -2415,66 +2520,9 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_vbat_mv != -EINVAL) ? VBAT_BASED_RECHG_BIT : 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge VBAT threshold */ if (chip->dt.auto_recharge_vbat_mv != -EINVAL) { u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv); temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8); rc = smblib_batch_write(chg, CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2); if (rc < 0) { dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n", rc); return rc; } /* Program the sample count for VBAT based recharge to 3 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); return rc; } } rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK, (chip->dt.auto_recharge_soc != -EINVAL) ? SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n", rc); return rc; } /* program the auto-recharge threshold */ if (chip->dt.auto_recharge_soc != -EINVAL) { pval.intval = chip->dt.auto_recharge_soc; rc = smblib_set_prop_rechg_soc_thresh(chg, &pval); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n", rc); return rc; } /* Program the sample count for SOC based recharge to 1 */ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG, NO_OF_SAMPLE_FOR_RCHG, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n", rc); rc = smb5_configure_recharging(chip); if (rc < 0) return rc; } } rc = smblib_disable_hw_jeita(chg, true); if (rc < 0) { Loading Loading @@ -3129,6 +3177,21 @@ static int smb5_probe(struct platform_device *pdev) goto cleanup; } /* Support reporting polarity and speed via properties */ rc = extcon_set_property_capability(chg->extcon, EXTCON_USB, EXTCON_PROP_USB_TYPEC_POLARITY); rc |= extcon_set_property_capability(chg->extcon, EXTCON_USB, EXTCON_PROP_USB_SS); rc |= extcon_set_property_capability(chg->extcon, EXTCON_USB_HOST, EXTCON_PROP_USB_TYPEC_POLARITY); rc |= extcon_set_property_capability(chg->extcon, EXTCON_USB_HOST, EXTCON_PROP_USB_SS); if (rc < 0) { dev_err(chg->dev, "failed to configure extcon capabilities\n"); goto cleanup; } rc = smb5_init_hw(chip); if (rc < 0) { pr_err("Couldn't initialize hardware rc=%d\n", rc); Loading
drivers/power/supply/qcom/smb1355-charger.c +14 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,9 @@ #define BATT_GT_PRE_TO_FAST_BIT BIT(4) #define ENABLE_CHARGING_BIT BIT(3) #define CHGR_CHARGING_ENABLE_CMD_REG (CHGR_BASE + 0x42) #define CHARGING_ENABLE_CMD_BIT BIT(0) #define CHGR_CFG2_REG (CHGR_BASE + 0x51) #define CHG_EN_SRC_BIT BIT(7) #define CHG_EN_POLARITY_BIT BIT(6) Loading Loading @@ -1032,7 +1035,17 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } /* disable parallel charging path */ /* * Disable command based SMB1355 enablement and disable parallel * charging path by switching to command based mode. */ rc = smb1355_masked_write(chip, CHGR_CHARGING_ENABLE_CMD_REG, CHARGING_ENABLE_CMD_BIT, 0); if (rc < 0) { pr_err("Coudln't configure command bit, rc=%d\n", rc); return rc; } rc = smb1355_set_parallel_charging(chip, true); if (rc < 0) { pr_err("Couldn't disable parallel path rc=%d\n", rc); Loading
drivers/power/supply/qcom/smb1390-charger-psy.c +52 −34 Original line number Diff line number Diff line Loading @@ -124,7 +124,6 @@ struct smb1390 { struct votable *ilim_votable; struct votable *fcc_votable; struct votable *fv_votable; struct votable *cp_awake_votable; /* power supplies */ struct power_supply *usb_psy; Loading @@ -138,7 +137,9 @@ struct smb1390 { struct smb1390_iio iio; int irq_status; int taper_entry_fv; bool switcher_disabled; bool switcher_enabled; int die_temp; bool suspended; }; struct smb_irq { Loading Loading @@ -276,8 +277,8 @@ static irqreturn_t default_irq_handler(int irq, void *data) rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, &enable); if (!rc) { if (chip->switcher_disabled == enable) { chip->switcher_disabled = !chip->switcher_disabled; if (chip->switcher_enabled != enable) { chip->switcher_enabled = enable; if (chip->fcc_votable) rerun_election(chip->fcc_votable); } Loading Loading @@ -424,7 +425,7 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, struct smb1390 *chip = data; int rc = 0; if (!is_psy_voter_available(chip)) if (!is_psy_voter_available(chip) || chip->suspended) return -EAGAIN; if (disable) { Loading @@ -432,10 +433,7 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, CMD_EN_SWITCHER_BIT, 0); if (rc < 0) return rc; vote(chip->cp_awake_votable, CP_VOTER, false, 0); } else { vote(chip->cp_awake_votable, CP_VOTER, true, 0); rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); if (rc < 0) Loading @@ -454,7 +452,7 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, struct smb1390 *chip = data; int rc = 0; if (!is_psy_voter_available(chip)) if (!is_psy_voter_available(chip) || chip->suspended) return -EAGAIN; /* ILIM should always have at least one active vote */ Loading Loading @@ -483,20 +481,6 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, return rc; } static int smb1390_awake_vote_cb(struct votable *votable, void *data, int awake, const char *client) { struct smb1390 *chip = data; if (awake) __pm_stay_awake(chip->cp_ws); else __pm_relax(chip->cp_ws); pr_debug("client: %s awake: %d\n", client, awake); return 0; } static int smb1390_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { Loading Loading @@ -705,12 +689,26 @@ static int smb1390_get_prop(struct power_supply *psy, !get_effective_result(chip->disable_votable); break; case POWER_SUPPLY_PROP_CP_SWITCHER_EN: rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, &enable); if (chip->suspended) { val->intval = chip->switcher_enabled; } else { rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, &enable); if (!rc) val->intval = enable; } break; case POWER_SUPPLY_PROP_CP_DIE_TEMP: if (chip->suspended) { if (chip->die_temp != -ENODATA) val->intval = chip->die_temp; else rc = -ENODATA; } else { rc = smb1390_get_die_temp(chip, val); if (rc >= 0) chip->die_temp = val->intval; } break; case POWER_SUPPLY_PROP_CP_ISNS: rc = smb1390_get_isns(chip, val); Loading Loading @@ -844,11 +842,6 @@ static void smb1390_release_channels(struct smb1390 *chip) static int smb1390_create_votables(struct smb1390 *chip) { chip->cp_awake_votable = create_votable("CP_AWAKE", VOTE_SET_ANY, smb1390_awake_vote_cb, chip); if (IS_ERR(chip->cp_awake_votable)) return PTR_ERR(chip->cp_awake_votable); chip->disable_votable = create_votable("CP_DISABLE", VOTE_SET_ANY, smb1390_disable_vote_cb, chip); if (IS_ERR(chip->disable_votable)) Loading Loading @@ -880,7 +873,6 @@ static void smb1390_destroy_votables(struct smb1390 *chip) { destroy_votable(chip->disable_votable); destroy_votable(chip->ilim_votable); destroy_votable(chip->cp_awake_votable); } static int smb1390_init_hw(struct smb1390 *chip) Loading Loading @@ -989,7 +981,8 @@ static int smb1390_probe(struct platform_device *pdev) chip->dev = &pdev->dev; spin_lock_init(&chip->status_change_lock); mutex_init(&chip->die_chan_lock); chip->switcher_disabled = true; chip->die_temp = -ENODATA; platform_set_drvdata(pdev, chip); chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { Loading Loading @@ -1071,6 +1064,30 @@ static int smb1390_remove(struct platform_device *pdev) return 0; } static int smb1390_suspend(struct device *dev) { struct smb1390 *chip = dev_get_drvdata(dev); chip->suspended = true; return 0; } static int smb1390_resume(struct device *dev) { struct smb1390 *chip = dev_get_drvdata(dev); chip->suspended = false; rerun_election(chip->ilim_votable); rerun_election(chip->disable_votable); return 0; } static const struct dev_pm_ops smb1390_pm_ops = { .suspend = smb1390_suspend, .resume = smb1390_resume, }; static const struct of_device_id match_table[] = { { .compatible = "qcom,smb1390-charger-psy", }, { }, Loading @@ -1079,6 +1096,7 @@ static const struct of_device_id match_table[] = { static struct platform_driver smb1390_driver = { .driver = { .name = "qcom,smb1390-charger-psy", .pm = &smb1390_pm_ops, .of_match_table = match_table, }, .probe = smb1390_probe, Loading
drivers/power/supply/qcom/smb5-lib.c +66 −30 Original line number Diff line number Diff line Loading @@ -1423,7 +1423,9 @@ static int smblib_set_moisture_protection(struct smb_charger *chg, /* Set 1% duty cycle on ID detection */ rc = smblib_masked_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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, Loading Loading @@ -1454,7 +1456,9 @@ static int smblib_set_moisture_protection(struct smb_charger *chg, } /* Disable periodic monitoring of CC_ID pin */ rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); rc = smblib_write(chg, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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); Loading Loading @@ -2730,6 +2734,11 @@ int smblib_get_prop_dc_present(struct smb_charger *chg, int rc; u8 stat; if (chg->smb_version == PMI632_SUBTYPE) { val->intval = 0; return 0; } rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc); Loading @@ -2746,6 +2755,11 @@ int smblib_get_prop_dc_online(struct smb_charger *chg, int rc = 0; u8 stat; if (chg->smb_version == PMI632_SUBTYPE) { val->intval = 0; return 0; } if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) { val->intval = false; return rc; Loading Loading @@ -4897,6 +4911,9 @@ static bool smblib_src_lpd(struct smb_charger *chg) u8 stat; int rc; if (chg->lpd_disabled) return false; 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 @@ -5139,12 +5156,35 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) chg->typec_mode, typec_mode); } static void smblib_lpd_launch_ra_open_work(struct smb_charger *chg) { u8 stat; int rc; if (chg->lpd_disabled) return; 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; } if (!(stat & TYPEC_TCCDEBOUNCE_DONE_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)); } } 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); Loading Loading @@ -5176,21 +5216,7 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) if (chg->pr_swap_in_progress || chg->pd_hard_reset) 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; } if (!(stat & TYPEC_TCCDEBOUNCE_DONE_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)); } smblib_lpd_launch_ra_open_work(chg); if (chg->usb_psy) power_supply_changed(chg->usb_psy); Loading Loading @@ -5225,6 +5251,16 @@ irqreturn_t typec_state_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } static void smblib_lpd_clear_ra_open_work(struct smb_charger *chg) { if (chg->lpd_disabled) return; cancel_delayed_work_sync(&chg->lpd_detach_work); chg->lpd_stage = LPD_STAGE_FLOAT_CANCEL; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, false, 0); } irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) { Loading @@ -5243,10 +5279,8 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) } if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) { cancel_delayed_work_sync(&chg->lpd_detach_work); chg->lpd_stage = LPD_STAGE_FLOAT_CANCEL; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, false, 0); smblib_lpd_clear_ra_open_work(chg); rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { Loading Loading @@ -5782,7 +5816,9 @@ static void smblib_moisture_protection_work(struct work_struct *work) * 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); rc = smblib_write(chg, ((chg->smb_version == PMI632_SUBTYPE) ? PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG : 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); Loading