// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021 The Linux Foundation. All rights reserved. * Copyright (c) 2022, 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include #include #include #include "smblite-lib.h" #include "smb5-iio.h" #include "smblite-reg.h" #include "schgm-flashlite.h" int smblite_iio_get_prop(struct smb_charger *chg, int channel, int *val) { union power_supply_propval pval = {0, }; int rc = 0; pval.intval = 0; *val = 0; switch (channel) { /* USB */ case PSY_IIO_USB_REAL_TYPE: *val = chg->real_charger_type; break; case PSY_IIO_TYPEC_MODE: rc = smblite_lib_get_usb_prop_typec_mode(chg, val); break; case PSY_IIO_TYPEC_POWER_ROLE: rc = smblite_lib_get_prop_typec_power_role(chg, val); break; case PSY_IIO_TYPEC_CC_ORIENTATION: rc = smblite_lib_get_prop_typec_cc_orientation(chg, val); break; case PSY_IIO_USB_INPUT_CURRENT_SETTLED: rc = smblite_lib_get_prop_input_current_settled(chg, val); break; case PSY_IIO_CONNECTOR_TYPE: *val = chg->connector_type; break; case PSY_IIO_HW_CURRENT_MAX: rc = smblite_lib_get_hw_current_max(chg, val); break; /* MAIN */ case PSY_IIO_MAIN_INPUT_CURRENT_SETTLED: rc = smblite_lib_get_prop_input_current_settled(chg, val); if (!rc) *val = pval.intval; break; case PSY_IIO_MAIN_INPUT_VOLTAGE_SETTLED: rc = smblite_lib_get_prop_input_voltage_settled(chg, val); break; case PSY_IIO_FCC_DELTA: val = 0; break; case PSY_IIO_FLASH_ACTIVE: *val = chg->flash_active; break; case PSY_IIO_FLASH_TRIGGER: *val = 0; rc = schgm_flashlite_get_vreg_ok(chg, val); break; case PSY_IIO_CURRENT_MAX: rc = smblite_lib_get_icl_current(chg, val); break; case PSY_IIO_VOLTAGE_MAX: rc = smblite_lib_get_charge_param(chg, &chg->param.fv, val); break; case PSY_IIO_CONSTANT_CHARGE_CURRENT_MAX: rc = smblite_lib_get_charge_param(chg, &chg->param.fcc, val); break; case PSY_IIO_MAIN_FCC_MAX: *val = chg->main_fcc_max; break; /* BATTERY */ case PSY_IIO_CHARGER_TEMP: rc = smblite_lib_get_prop_charger_temp(chg, val); break; case PSY_IIO_SW_JEITA_ENABLED: *val = 1; break; case PSY_IIO_PARALLEL_DISABLE: *val = get_client_vote(chg->pl_disable_votable, USER_VOTER); break; case PSY_IIO_CHARGE_DONE: rc = smblite_lib_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_INPUT_CURRENT_LIMITED: rc = smblite_lib_get_prop_input_current_limited(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_DIE_HEALTH: rc = smblite_lib_get_die_health(chg, val); break; case PSY_IIO_TYPEC_ACCESSORY_MODE: rc = smblite_lib_get_usb_prop_typec_accessory_mode(chg, val); break; default: pr_debug("get prop %x is not supported\n", channel); return -EINVAL; } if (rc < 0) { pr_err("Couldn't get prop %x rc = %d\n", channel, rc); return rc; } return IIO_VAL_INT; } int smblite_iio_set_prop(struct smb_charger *chg, int channel, int val) { union power_supply_propval pval = {0, }; int icl_ua, rc = 0; switch (channel) { /* USB */ case PSY_IIO_USB_REAL_TYPE: rc = smblite_lib_set_prop_usb_type(chg, val); break; case PSY_IIO_TYPEC_POWER_ROLE: rc = smblite_lib_set_prop_typec_power_role(chg, val); break; /* MAIN */ case PSY_IIO_FLASH_ACTIVE: if (chg->flash_active != val) { chg->flash_active = val; rc = smblite_lib_get_prop_usb_present(chg, &pval); if (rc < 0) pr_err("Failed to get USB present status rc=%d\n", rc); if (!pval.intval) { /* vote 100ma when usb is not present*/ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, USBIN_100UA); } else if (chg->flash_active) { icl_ua = get_effective_result_locked( chg->usb_icl_votable); if (icl_ua >= USBIN_400UA) { vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, true, icl_ua - USBIN_300UA); } } else { vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, false, 0); } pr_debug("flash_active=%d usb_present=%d icl=%d\n", chg->flash_active, pval.intval, get_effective_result_locked( chg->usb_icl_votable)); } break; case PSY_IIO_VOLTAGE_MAX: rc = smblite_lib_set_charge_param(chg, &chg->param.fv, val); break; case PSY_IIO_CURRENT_MAX: rc = smblite_lib_set_icl_current(chg, val); break; case PSY_IIO_CONSTANT_CHARGE_CURRENT_MAX: rc = smblite_lib_set_charge_param(chg, &chg->param.fcc, val); break; case PSY_IIO_MAIN_FCC_MAX: chg->main_fcc_max = val; rerun_election(chg->fcc_votable); break; /* BATTERY */ 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 = smblite_lib_set_prop_ship_mode(chg, val); break; case PSY_IIO_RECHARGE_SOC: rc = smblite_lib_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; case PSY_IIO_DIE_HEALTH: power_supply_changed(chg->batt_psy); break; case PSY_IIO_SYS_SOC: rc = smblite_lib_set_prop_batt_sys_soc(chg, val); break; default: pr_debug("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_SMB5 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