123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/delay.h>
- #include <linux/pmic-voter.h>
- #include <linux/power_supply.h>
- #include <linux/iio/consumer.h>
- #include "smb5-lib.h"
- #include "smb5-iio.h"
- #include "smb5-reg.h"
- #include "schgm-flash.h"
- #define MIN_THERMAL_VOTE_UA 500000
- int smb5_iio_get_prop(struct smb_charger *chg, int channel, int *val)
- {
- union power_supply_propval pval = {0, };
- int rc = 0;
- u8 reg = 0, buff[2] = {0};
- pval.intval = 0;
- *val = 0;
- switch (channel) {
- /* USB */
- case PSY_IIO_VOLTAGE_MAX_LIMIT:
- if (chg->usbin_forced_max_uv) {
- *val = chg->usbin_forced_max_uv;
- } else {
- rc = smblib_get_prop_usb_voltage_max_design(chg, &pval);
- *val = pval.intval;
- }
- break;
- case PSY_IIO_PD_CURRENT_MAX:
- *val = get_client_vote(chg->usb_icl_votable, PD_VOTER);
- break;
- case PSY_IIO_USB_REAL_TYPE:
- *val = chg->real_charger_type;
- break;
- case PSY_IIO_TYPEC_MODE:
- rc = smblib_get_usb_prop_typec_mode(chg, val);
- break;
- case PSY_IIO_TYPEC_POWER_ROLE:
- rc = smblib_get_prop_typec_power_role(chg, val);
- break;
- case PSY_IIO_TYPEC_CC_ORIENTATION:
- rc = smblib_get_prop_typec_cc_orientation(chg, val);
- break;
- case PSY_IIO_TYPEC_SRC_RP:
- rc = smblib_get_prop_typec_select_rp(chg, val);
- break;
- case PSY_IIO_PD_ACTIVE:
- *val = chg->pd_active;
- break;
- case PSY_IIO_USB_INPUT_CURRENT_SETTLED:
- rc = smblib_get_prop_input_current_settled(chg, &pval);
- if (!rc)
- *val = pval.intval;
- break;
- case PSY_IIO_PD_IN_HARD_RESET:
- rc = smblib_get_prop_pd_in_hard_reset(chg, val);
- break;
- case PSY_IIO_PD_USB_SUSPEND_SUPPORTED:
- *val = chg->system_suspend_supported;
- break;
- case PSY_IIO_PE_START:
- rc = smblib_get_pe_start(chg, val);
- break;
- case PSY_IIO_CTM_CURRENT_MAX:
- *val = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
- break;
- case PSY_IIO_HW_CURRENT_MAX:
- rc = smblib_get_charge_current(chg, val);
- break;
- case PSY_IIO_PR_SWAP:
- rc = smblib_get_prop_pr_swap_in_progress(chg, val);
- break;
- case PSY_IIO_PD_VOLTAGE_MAX:
- *val = chg->voltage_max_uv;
- break;
- case PSY_IIO_PD_VOLTAGE_MIN:
- *val = chg->voltage_min_uv;
- break;
- case PSY_IIO_VOLTAGE_QNOVO:
- *val = get_client_vote_locked(chg->fv_votable,
- QNOVO_VOTER);
- break;
- case PSY_IIO_CURRENT_QNOVO:
- *val = get_client_vote_locked(chg->fcc_votable,
- QNOVO_VOTER);
- break;
- case PSY_IIO_CONNECTOR_TYPE:
- *val = chg->connector_type;
- break;
- case PSY_IIO_CONNECTOR_HEALTH:
- *val = smblib_get_prop_connector_health(chg);
- break;
- case PSY_IIO_SMB_EN_MODE:
- mutex_lock(&chg->smb_lock);
- *val = chg->sec_chg_selected;
- mutex_unlock(&chg->smb_lock);
- break;
- case PSY_IIO_SMB_EN_REASON:
- *val = chg->cp_reason;
- break;
- case PSY_IIO_MOISTURE_DETECTED:
- *val = chg->moisture_present;
- break;
- case PSY_IIO_MOISTURE_DETECTION_EN:
- *val = !chg->lpd_disabled;
- break;
- case PSY_IIO_HVDCP_OPTI_ALLOWED:
- *val = !chg->flash_active;
- break;
- case PSY_IIO_QC_OPTI_DISABLE:
- if (chg->hw_die_temp_mitigation)
- *val = QC_THERMAL_BALANCE_DISABLE
- | QC_INOV_THERMAL_DISABLE;
- if (chg->hw_connector_mitigation)
- *val |= QC_CTM_DISABLE;
- break;
- case PSY_IIO_VOLTAGE_VPH:
- rc = smblib_get_prop_vph_voltage_now(chg, val);
- break;
- case PSY_IIO_THERM_ICL_LIMIT:
- *val = get_client_vote(chg->usb_icl_votable,
- THERMAL_THROTTLE_VOTER);
- break;
- case PSY_IIO_ADAPTER_CC_MODE:
- *val = chg->adapter_cc_mode;
- break;
- case PSY_IIO_SKIN_HEALTH:
- *val = smblib_get_skin_temp_status(chg);
- break;
- case PSY_IIO_APSD_RERUN:
- *val = 0;
- break;
- case PSY_IIO_APSD_TIMEOUT:
- *val = chg->apsd_ext_timeout;
- break;
- case PSY_IIO_CHARGER_STATUS:
- *val = 0;
- if (chg->sdam_base) {
- rc = smblib_read(chg,
- chg->sdam_base + SDAM_QC_DET_STATUS_REG, ®);
- if (!rc)
- *val = reg;
- }
- break;
- case PSY_IIO_USB_INPUT_VOLTAGE_SETTLED:
- *val = 0;
- if (chg->sdam_base) {
- rc = smblib_batch_read(chg,
- chg->sdam_base + SDAM_QC_ADC_LSB_REG, buff, 2);
- if (!rc)
- *val = (buff[1] << 8 | buff[0]) * 1038;
- }
- break;
- /* MAIN */
- case PSY_IIO_MAIN_INPUT_CURRENT_SETTLED:
- rc = smblib_get_prop_input_current_settled(chg, &pval);
- if (!rc)
- *val = pval.intval;
- break;
- case PSY_IIO_MAIN_INPUT_VOLTAGE_SETTLED:
- rc = smblib_get_prop_input_voltage_settled(chg, val);
- break;
- case PSY_IIO_FCC_DELTA:
- rc = smblib_get_prop_fcc_delta(chg, val);
- break;
- case PSY_IIO_FLASH_ACTIVE:
- *val = chg->flash_active;
- break;
- case PSY_IIO_FLASH_TRIGGER:
- *val = 0;
- if (chg->chg_param.smb_version == PMI632)
- rc = schgm_flash_get_vreg_ok(chg, val);
- break;
- case PSY_IIO_TOGGLE_STAT:
- *val = 0;
- break;
- case PSY_IIO_MAIN_FCC_MAX:
- *val = chg->main_fcc_max;
- break;
- case PSY_IIO_IRQ_STATUS:
- rc = smblib_get_irq_status(chg, val);
- break;
- case PSY_IIO_FORCE_MAIN_FCC:
- rc = smblib_get_charge_param(chg, &chg->param.fcc,
- val);
- break;
- case PSY_IIO_FORCE_MAIN_ICL:
- rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
- val);
- break;
- case PSY_IIO_COMP_CLAMP_LEVEL:
- *val = chg->comp_clamp_level;
- break;
- /* Use this property to report overheat status */
- case PSY_IIO_HOT_TEMP:
- *val = chg->thermal_overheat;
- break;
- case PSY_IIO_VOLTAGE_MAX:
- rc = smblib_get_charge_param(chg, &chg->param.fv, val);
- break;
- case PSY_IIO_CONSTANT_CHARGE_CURRENT_MAX:
- rc = smblib_get_charge_param(chg, &chg->param.fcc,
- val);
- break;
- case PSY_IIO_CURRENT_MAX:
- rc = smblib_get_icl_current(chg, val);
- break;
- case PSY_IIO_HEALTH:
- rc = *val = smblib_get_prop_smb_health(chg);
- break;
- /* DC */
- case PSY_IIO_DC_REAL_TYPE:
- *val = POWER_SUPPLY_TYPE_MAINS;
- break;
- case PSY_IIO_INPUT_VOLTAGE_REGULATION:
- rc = smblib_get_prop_voltage_wls_output(chg, &pval);
- if (!rc)
- *val = pval.intval;
- break;
- case PSY_IIO_DC_RESET:
- *val = 0;
- break;
- case PSY_IIO_AICL_DONE:
- *val = chg->dcin_aicl_done;
- break;
- /* BATTERY */
- case PSY_IIO_CHARGER_TEMP:
- rc = smblib_get_prop_charger_temp(chg, val);
- break;
- case PSY_IIO_CHARGER_TEMP_MAX:
- *val = chg->charger_temp_max;
- break;
- case PSY_IIO_SW_JEITA_ENABLED:
- *val = chg->sw_jeita_enabled;
- break;
- case PSY_IIO_PARALLEL_DISABLE:
- *val = get_client_vote(chg->pl_disable_votable,
- USER_VOTER);
- break;
- case PSY_IIO_CHARGE_DONE:
- rc = smblib_get_prop_batt_charge_done(chg, val);
- break;
- case PSY_IIO_SET_SHIP_MODE:
- /* Not in ship mode as long as device is active */
- *val = 0;
- break;
- case PSY_IIO_RERUN_AICL:
- *val = 0;
- break;
- case PSY_IIO_DP_DM:
- *val = chg->pulse_cnt;
- break;
- case PSY_IIO_INPUT_CURRENT_LIMITED:
- rc = smblib_get_prop_input_current_limited(chg, val);
- break;
- case PSY_IIO_DIE_HEALTH:
- rc = smblib_get_die_health(chg, val);
- break;
- case PSY_IIO_RECHARGE_SOC:
- *val = chg->auto_recharge_soc;
- break;
- case PSY_IIO_FORCE_RECHARGE:
- *val = 0;
- break;
- case PSY_IIO_FCC_STEPPER_ENABLE:
- *val = chg->fcc_stepper_enable;
- break;
- case PSY_IIO_TYPEC_ACCESSORY_MODE:
- rc = smblib_get_usb_prop_typec_accessory_mode(chg, val);
- break;
- default:
- pr_err("get prop %d is not supported\n", channel);
- rc = -EINVAL;
- break;
- }
- if (rc < 0) {
- pr_err("Couldn't get prop %d rc = %d\n", channel, rc);
- return rc;
- }
- return IIO_VAL_INT;
- }
- int smb5_iio_set_prop(struct smb_charger *chg, int channel, int val)
- {
- union power_supply_propval pval = {0, };
- int real_chg_type = chg->real_charger_type;
- int icl, rc = 0, offset_ua = 0;
- switch (channel) {
- /* USB */
- case PSY_IIO_PD_CURRENT_MAX:
- rc = smblib_set_prop_pd_current_max(chg, val);
- break;
- case PSY_IIO_TYPEC_POWER_ROLE:
- rc = smblib_set_prop_typec_power_role(chg, val);
- break;
- case PSY_IIO_TYPEC_SRC_RP:
- rc = smblib_set_prop_typec_select_rp(chg, val);
- break;
- case PSY_IIO_PD_ACTIVE:
- rc = smblib_set_prop_pd_active(chg, val);
- break;
- case PSY_IIO_PD_IN_HARD_RESET:
- rc = smblib_set_prop_pd_in_hard_reset(chg, val);
- break;
- case PSY_IIO_PD_USB_SUSPEND_SUPPORTED:
- chg->system_suspend_supported = val;
- break;
- case PSY_IIO_CTM_CURRENT_MAX:
- rc = vote(chg->usb_icl_votable, CTM_VOTER,
- val >= 0, val);
- break;
- case PSY_IIO_PR_SWAP:
- rc = smblib_set_prop_pr_swap_in_progress(chg, val);
- break;
- case PSY_IIO_PD_VOLTAGE_MAX:
- rc = smblib_set_prop_pd_voltage_max(chg, val);
- break;
- case PSY_IIO_PD_VOLTAGE_MIN:
- rc = smblib_set_prop_pd_voltage_min(chg, val);
- break;
- case PSY_IIO_VOLTAGE_QNOVO:
- if (val == -EINVAL) {
- vote(chg->fv_votable, BATT_PROFILE_VOTER, true,
- chg->batt_profile_fv_uv);
- vote(chg->fv_votable, QNOVO_VOTER, false, 0);
- } else {
- vote(chg->fv_votable, QNOVO_VOTER, true, val);
- vote(chg->fv_votable, BATT_PROFILE_VOTER, false, 0);
- }
- break;
- case PSY_IIO_CURRENT_QNOVO:
- vote(chg->pl_disable_votable, PL_QNOVO_VOTER,
- val != -EINVAL && val < 2000000, 0);
- if (val == -EINVAL) {
- vote(chg->fcc_votable, BATT_PROFILE_VOTER,
- true, chg->batt_profile_fcc_ua);
- vote(chg->fcc_votable, QNOVO_VOTER, false, 0);
- } else {
- vote(chg->fcc_votable, QNOVO_VOTER, true, val);
- vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0);
- }
- break;
- case PSY_IIO_CONNECTOR_HEALTH:
- chg->connector_health = val;
- if (chg->usb_psy)
- power_supply_changed(chg->usb_psy);
- break;
- case PSY_IIO_THERM_ICL_LIMIT:
- if (!is_client_vote_enabled(chg->usb_icl_votable,
- THERMAL_THROTTLE_VOTER)) {
- chg->init_thermal_ua = get_effective_result(
- chg->usb_icl_votable);
- icl = chg->init_thermal_ua + val;
- } else {
- icl = get_client_vote(chg->usb_icl_votable,
- THERMAL_THROTTLE_VOTER) + val;
- }
- if (icl >= MIN_THERMAL_VOTE_UA)
- rc = vote(chg->usb_icl_votable, THERMAL_THROTTLE_VOTER,
- (icl != chg->init_thermal_ua), icl);
- else
- rc = -EINVAL;
- break;
- case PSY_IIO_VOLTAGE_MAX_LIMIT:
- smblib_set_prop_usb_voltage_max_limit(chg, val);
- break;
- case PSY_IIO_ADAPTER_CC_MODE:
- chg->adapter_cc_mode = val;
- break;
- case PSY_IIO_APSD_RERUN:
- del_timer_sync(&chg->apsd_timer);
- chg->apsd_ext_timeout = false;
- smblib_rerun_apsd(chg);
- break;
- case PSY_IIO_MOISTURE_DETECTION_EN:
- smblib_moisture_detection_enable(chg, val);
- break;
- /* MAIN */
- case PSY_IIO_FLASH_ACTIVE:
- if ((chg->chg_param.smb_version == PMI632)
- && (chg->flash_active != val)) {
- chg->flash_active = val;
- rc = smblib_get_prop_usb_present(chg, &pval);
- if (rc < 0)
- pr_err("Failed to get USB preset status rc=%d\n",
- rc);
- if (pval.intval) {
- rc = smblib_force_vbus_voltage(chg,
- chg->flash_active ? FORCE_5V_BIT
- : IDLE_BIT);
- if (rc < 0)
- pr_err("Failed to force 5V\n");
- else
- chg->pulse_cnt = 0;
- } else {
- /* USB absent & flash not-active - vote 100mA */
- vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER,
- true, SDP_100_MA);
- }
- pr_debug("flash active VBUS 5V restriction %s\n",
- chg->flash_active ? "applied" : "removed");
- /* Update userspace */
- if (chg->batt_psy)
- power_supply_changed(chg->batt_psy);
- }
- break;
- case PSY_IIO_TOGGLE_STAT:
- rc = smblib_toggle_smb_en(chg, val);
- break;
- case PSY_IIO_MAIN_FCC_MAX:
- chg->main_fcc_max = val;
- rerun_election(chg->fcc_votable);
- break;
- case PSY_IIO_FORCE_MAIN_FCC:
- vote_override(chg->fcc_main_votable, CC_MODE_VOTER,
- (val < 0) ? false : true, val);
- if (val >= 0)
- chg->chg_param.forced_main_fcc = val;
- /*
- * Remove low vote on FCC_MAIN, for WLS, to allow FCC_MAIN to
- * rise to its full value.
- */
- if (val < 0)
- vote(chg->fcc_main_votable, WLS_PL_CHARGING_VOTER,
- false, 0);
- /* Main FCC updated re-calculate FCC */
- rerun_election(chg->fcc_votable);
- break;
- case PSY_IIO_FORCE_MAIN_ICL:
- vote_override(chg->usb_icl_votable, CC_MODE_VOTER,
- (val < 0) ? false : true, val);
- /* Main ICL updated re-calculate ILIM */
- if (real_chg_type == QTI_POWER_SUPPLY_TYPE_USB_HVDCP_3 ||
- real_chg_type == QTI_POWER_SUPPLY_TYPE_USB_HVDCP_3P5)
- rerun_election(chg->fcc_votable);
- break;
- #ifdef CONFIG_QPNP_SMB5
- case PSY_IIO_COMP_CLAMP_LEVEL:
- rc = smb5_set_prop_comp_clamp_level(chg, val);
- break;
- #endif
- case PSY_IIO_HOT_TEMP:
- rc = smblib_set_prop_thermal_overheat(chg, val);
- break;
- case PSY_IIO_VOLTAGE_MAX:
- rc = smblib_set_charge_param(chg, &chg->param.fv, val);
- break;
- case PSY_IIO_CONSTANT_CHARGE_CURRENT_MAX:
- /* Adjust Main FCC for QC3.0 + SMB1390 */
- rc = smblib_get_qc3_main_icl_offset(chg, &offset_ua);
- if (rc < 0)
- offset_ua = 0;
- rc = smblib_set_charge_param(chg, &chg->param.fcc,
- val + offset_ua);
- break;
- case PSY_IIO_CURRENT_MAX:
- rc = smblib_set_icl_current(chg, val);
- break;
- /* DC */
- case PSY_IIO_INPUT_VOLTAGE_REGULATION:
- pval.intval = val;
- rc = smblib_set_prop_voltage_wls_output(chg, &pval);
- break;
- case PSY_IIO_DC_RESET:
- rc = smblib_set_prop_dc_reset(chg);
- break;
- /* BATTERY */
- case PSY_IIO_PARALLEL_DISABLE:
- vote(chg->pl_disable_votable, USER_VOTER, (bool)val, 0);
- break;
- case PSY_IIO_SET_SHIP_MODE:
- /* Not in ship mode as long as the device is active */
- if (!val)
- break;
- if (chg->iio_chan_list_smb_parallel)
- rc = iio_write_channel_raw(
- chg->iio_chan_list_smb_parallel[SMB_SET_SHIP_MODE],
- val);
- rc = smblib_set_prop_ship_mode(chg, val);
- break;
- case PSY_IIO_RERUN_AICL:
- rc = smblib_run_aicl(chg, RERUN_AICL);
- break;
- case PSY_IIO_DP_DM:
- if (!chg->flash_active)
- rc = smblib_dp_dm(chg, val);
- break;
- case PSY_IIO_INPUT_CURRENT_LIMITED:
- rc = smblib_set_prop_input_current_limited(chg, val);
- break;
- case PSY_IIO_DIE_HEALTH:
- chg->die_health = val;
- if (chg->batt_psy)
- power_supply_changed(chg->batt_psy);
- break;
- case PSY_IIO_RECHARGE_SOC:
- rc = smblib_set_prop_rechg_soc_thresh(chg, val);
- break;
- case PSY_IIO_FORCE_RECHARGE:
- /* toggle charging to force recharge */
- vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
- true, 0);
- /* charge disable delay */
- msleep(50);
- vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
- false, 0);
- break;
- case PSY_IIO_FCC_STEPPER_ENABLE:
- chg->fcc_stepper_enable = val;
- break;
- default:
- pr_err("get prop %d is not supported\n", channel);
- rc = -EINVAL;
- break;
- }
- if (rc < 0) {
- pr_err("Couldn't set prop %d rc = %d\n", channel, rc);
- return rc;
- }
- return 0;
- }
- #ifndef CONFIG_QPNP_SMBLITE
- struct iio_channel **get_ext_channels(struct device *dev,
- const char *const *channel_map, int size)
- {
- int i, rc = 0;
- struct iio_channel **iio_ch_ext;
- iio_ch_ext = devm_kcalloc(dev, size, sizeof(*iio_ch_ext), GFP_KERNEL);
- if (!iio_ch_ext)
- return ERR_PTR(-ENOMEM);
- for (i = 0; i < size; i++) {
- iio_ch_ext[i] = devm_iio_channel_get(dev, channel_map[i]);
- if (IS_ERR(iio_ch_ext[i])) {
- rc = PTR_ERR(iio_ch_ext[i]);
- if (rc != -EPROBE_DEFER)
- dev_err(dev, "%s channel unavailable, %d\n",
- channel_map[i], rc);
- return ERR_PTR(rc);
- }
- }
- return iio_ch_ext;
- }
- #endif
|