// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. */ /* * * Filename: * --------- * mtk_charger.c * * Project: * -------- * Android_Software * * Description: * ------------ * This Module defines functions of Battery charging * * Author: * ------- * Wy Chuang * */ #include /* For init/exit macros */ #include /* For MODULE_ marcros */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* necessary header */ #include "mtk_pe.h" #include "charger_class.h" /* dependent on platform */ #include "mtk_charger.h" struct pe_hal { struct charger_device *chg1_dev; struct charger_device *chg2_dev; }; int pe_hal_init_hardware(struct chg_alg_device *alg) { struct mtk_pe *pe; struct pe_hal *hal; pr_notice("%s\n", __func__); if (alg == NULL) { pr_notice("%s: alg is null\n", __func__); return -EINVAL; } pe = dev_get_drvdata(&alg->dev); hal = chg_alg_dev_get_drv_hal_data(alg); if (hal == NULL) { hal = devm_kzalloc(&pe->pdev->dev, sizeof(*hal), GFP_KERNEL); if (!hal) return -ENOMEM; chg_alg_dev_set_drv_hal_data(alg, hal); } hal->chg1_dev = get_charger_by_name("primary_chg"); if (hal->chg1_dev) pr_notice("%s: Found primary charger\n", __func__); else { pr_notice("%s: Error : can't find primary charger\n", __func__); return -ENODEV; } return 0; } static int get_pmic_vbus(int *vchr) { union power_supply_propval prop; static struct power_supply *chg_psy; int ret; if (chg_psy == NULL) chg_psy = power_supply_get_by_name("mtk_charger_type"); if (chg_psy == NULL || IS_ERR(chg_psy)) { pr_notice("%s Couldn't get chg_psy\n", __func__); ret = -1; } else { ret = power_supply_get_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop); } *vchr = prop.intval * 1000; pr_notice("%s vbus:%d\n", __func__, prop.intval); return ret; } /* Unit of the following functions are uV, uA */ int pe_hal_get_vbus(struct chg_alg_device *alg) { int ret = 0; int vchr = 0; struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); ret = charger_dev_get_vbus(hal->chg1_dev, &vchr); if (ret < 0) { ret = get_pmic_vbus(&vchr); if (ret < 0) pr_notice("%s: get vbus failed: %d\n", __func__, ret); } return vchr; } int pe_hal_get_ibat(struct chg_alg_device *alg) { union power_supply_propval prop; struct power_supply *bat_psy = NULL; int ret; struct mtk_pe *pe; if (alg == NULL) return -EINVAL; pe = dev_get_drvdata(&alg->dev); bat_psy = pe->bat_psy; if (bat_psy == NULL || IS_ERR(bat_psy)) { pr_notice("%s retry to get pe->bat_psy\n", __func__); bat_psy = devm_power_supply_get_by_phandle(&pe->pdev->dev, "gauge"); pe->bat_psy = bat_psy; } if (bat_psy == NULL || IS_ERR(bat_psy)) { pr_notice("%s Couldn't get bat_psy\n", __func__); ret = 0; } else { ret = power_supply_get_property(bat_psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); ret = prop.intval; } pr_debug("%s:%d\n", __func__, ret); return ret; } int pe_hal_get_charging_current(struct chg_alg_device *alg, enum chg_idx chgidx, u32 *ua) { struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); if (chgidx == CHG1 && hal->chg1_dev != NULL) charger_dev_get_charging_current(hal->chg1_dev, ua); else if (chgidx == CHG2 && hal->chg2_dev != NULL) charger_dev_get_charging_current(hal->chg2_dev, ua); pr_notice("%s idx:%d %d\n", __func__, chgidx, ua); return 0; } /* Enable/Disable HW & SW VBUS OVP */ int pe_hal_enable_vbus_ovp(struct chg_alg_device *alg, bool enable) { mtk_chg_enable_vbus_ovp(enable); return 0; } int pe_hal_enable_charging(struct chg_alg_device *alg, bool enable) { int ret = 0; struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); ret = charger_dev_enable(hal->chg1_dev, enable); if (ret < 0) chr_err("%s: failed, ret = %d\n", __func__, ret); return ret; } int pe_hal_set_mivr(struct chg_alg_device *alg, enum chg_idx chgidx, int uV) { int ret = 0; struct mtk_pe *pe; struct pe_hal *hal; if (alg == NULL) return -EINVAL; pe = dev_get_drvdata(&alg->dev); hal = chg_alg_dev_get_drv_hal_data(alg); ret = charger_dev_set_mivr(hal->chg1_dev, uV); if (ret < 0) pr_notice("%s: failed, ret = %d\n", __func__, ret); return ret; } int pe_hal_get_uisoc(struct chg_alg_device *alg) { union power_supply_propval prop; struct power_supply *bat_psy = NULL; int ret; struct mtk_pe *pe; if (alg == NULL) return -EINVAL; pe = dev_get_drvdata(&alg->dev); bat_psy = pe->bat_psy; if (bat_psy == NULL || IS_ERR(bat_psy)) { pr_notice("%s retry to get pe->bat_psy\n", __func__); bat_psy = devm_power_supply_get_by_phandle(&pe->pdev->dev, "gauge"); pe->bat_psy = bat_psy; } if (bat_psy == NULL || IS_ERR(bat_psy)) { pr_notice("%s Couldn't get bat_psy\n", __func__); ret = 50; } else { ret = power_supply_get_property(bat_psy, POWER_SUPPLY_PROP_CAPACITY, &prop); ret = prop.intval; } pr_notice("%s:%d\n", __func__, ret); return ret; } int pe_hal_get_charger_type(struct chg_alg_device *alg) { struct mtk_charger *info = NULL; struct power_supply *chg_psy = NULL; int ret = 0; if (alg == NULL) return -EINVAL; chg_psy = power_supply_get_by_name("mtk-master-charger"); if (chg_psy == NULL || IS_ERR(chg_psy)) { pr_notice("%s Couldn't get chg_psy\n", __func__); return -EINVAL; } else { info = (struct mtk_charger *)power_supply_get_drvdata(chg_psy); if (info == NULL) return -EINVAL; ret = info->chr_type; } pr_notice("%s type:%d\n", __func__, ret); return info->chr_type; } int pe_hal_send_ta_current_pattern(struct chg_alg_device *alg, bool increase) { struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); return charger_dev_send_ta_current_pattern(hal->chg1_dev, increase); } int pe_hal_get_charger_cnt(struct chg_alg_device *alg) { struct pe_hal *hal; int cnt = 0; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); if (hal->chg1_dev != NULL) cnt++; if (hal->chg2_dev != NULL) cnt++; return cnt; } bool pe_hal_is_chip_enable(struct chg_alg_device *alg, enum chg_idx chgidx) { struct pe_hal *hal; bool is_chip_enable = false; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); if (chgidx == CHG1) charger_dev_is_chip_enabled(hal->chg1_dev, &is_chip_enable); else if (chgidx == CHG2) charger_dev_is_chip_enabled(hal->chg2_dev, &is_chip_enable); return is_chip_enable; } int pe_hal_enable_chip(struct chg_alg_device *alg, enum chg_idx chgidx, bool en) { struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); if (chgidx == CHG1) charger_dev_enable_chip(hal->chg1_dev, en); else if (chgidx == CHG2) charger_dev_enable_chip(hal->chg2_dev, en); return 0; } int pe_hal_reset_ta(struct chg_alg_device *alg, enum chg_idx chgidx) { struct pe_hal *hal; int ret; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); ret = charger_dev_reset_ta(hal->chg1_dev); if (ret != 0) return -1; return 0; } int pe_hal_set_cv(struct chg_alg_device *alg, enum chg_idx chgidx, u32 uv) { struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); charger_dev_set_constant_voltage(hal->chg1_dev, uv); return 0; } int pe_hal_set_charging_current(struct chg_alg_device *alg, enum chg_idx chgidx, u32 ua) { struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); charger_dev_set_charging_current(hal->chg1_dev, ua); return 0; } int pe_hal_set_input_current(struct chg_alg_device *alg, enum chg_idx chgidx, u32 ua) { struct pe_hal *hal; if (alg == NULL) return -EINVAL; hal = chg_alg_dev_get_drv_hal_data(alg); charger_dev_set_input_current(hal->chg1_dev, ua); return 0; }