10819 lines
355 KiB
C
10819 lines
355 KiB
C
/*
|
|
* sec_battery.c
|
|
* Samsung Mobile Battery Driver
|
|
*
|
|
* Copyright (C) 2017 Samsung Electronics, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
#include "include/sec_battery.h"
|
|
|
|
#if defined(CONFIG_SEC_ABC)
|
|
#include <linux/sti/abc_common.h>
|
|
#endif
|
|
|
|
bool sleep_mode = false;
|
|
|
|
static struct device_attribute sec_battery_attrs[] = {
|
|
SEC_BATTERY_ATTR(batt_reset_soc),
|
|
SEC_BATTERY_ATTR(batt_read_raw_soc),
|
|
SEC_BATTERY_ATTR(batt_read_adj_soc),
|
|
SEC_BATTERY_ATTR(batt_type),
|
|
SEC_BATTERY_ATTR(batt_vfocv),
|
|
SEC_BATTERY_ATTR(batt_vol_adc),
|
|
SEC_BATTERY_ATTR(batt_vol_adc_cal),
|
|
SEC_BATTERY_ATTR(batt_vol_aver),
|
|
SEC_BATTERY_ATTR(batt_vol_adc_aver),
|
|
SEC_BATTERY_ATTR(batt_current_ua_now),
|
|
SEC_BATTERY_ATTR(batt_current_ua_avg),
|
|
SEC_BATTERY_ATTR(batt_filter_cfg),
|
|
SEC_BATTERY_ATTR(batt_temp),
|
|
SEC_BATTERY_ATTR(batt_temp_adc),
|
|
SEC_BATTERY_ATTR(batt_temp_aver),
|
|
SEC_BATTERY_ATTR(batt_temp_adc_aver),
|
|
SEC_BATTERY_ATTR(usb_temp),
|
|
SEC_BATTERY_ATTR(usb_temp_adc),
|
|
SEC_BATTERY_ATTR(chg_temp),
|
|
SEC_BATTERY_ATTR(chg_temp_adc),
|
|
SEC_BATTERY_ATTR(slave_chg_temp),
|
|
SEC_BATTERY_ATTR(slave_chg_temp_adc),
|
|
|
|
SEC_BATTERY_ATTR(batt_vf_adc),
|
|
SEC_BATTERY_ATTR(batt_slate_mode),
|
|
|
|
SEC_BATTERY_ATTR(batt_lp_charging),
|
|
SEC_BATTERY_ATTR(siop_activated),
|
|
SEC_BATTERY_ATTR(siop_level),
|
|
SEC_BATTERY_ATTR(siop_event),
|
|
SEC_BATTERY_ATTR(batt_charging_source),
|
|
SEC_BATTERY_ATTR(fg_reg_dump),
|
|
SEC_BATTERY_ATTR(fg_reset_cap),
|
|
SEC_BATTERY_ATTR(fg_capacity),
|
|
SEC_BATTERY_ATTR(fg_asoc),
|
|
SEC_BATTERY_ATTR(auth),
|
|
SEC_BATTERY_ATTR(chg_current_adc),
|
|
SEC_BATTERY_ATTR(wc_adc),
|
|
SEC_BATTERY_ATTR(wc_status),
|
|
SEC_BATTERY_ATTR(wc_enable),
|
|
SEC_BATTERY_ATTR(wc_control),
|
|
SEC_BATTERY_ATTR(wc_control_cnt),
|
|
SEC_BATTERY_ATTR(led_cover),
|
|
SEC_BATTERY_ATTR(hv_charger_status),
|
|
SEC_BATTERY_ATTR(hv_wc_charger_status),
|
|
SEC_BATTERY_ATTR(hv_charger_set),
|
|
SEC_BATTERY_ATTR(factory_mode),
|
|
SEC_BATTERY_ATTR(store_mode),
|
|
SEC_BATTERY_ATTR(update),
|
|
SEC_BATTERY_ATTR(test_mode),
|
|
|
|
SEC_BATTERY_ATTR(call),
|
|
SEC_BATTERY_ATTR(2g_call),
|
|
SEC_BATTERY_ATTR(talk_gsm),
|
|
SEC_BATTERY_ATTR(3g_call),
|
|
SEC_BATTERY_ATTR(talk_wcdma),
|
|
SEC_BATTERY_ATTR(music),
|
|
SEC_BATTERY_ATTR(video),
|
|
SEC_BATTERY_ATTR(browser),
|
|
SEC_BATTERY_ATTR(hotspot),
|
|
SEC_BATTERY_ATTR(camera),
|
|
SEC_BATTERY_ATTR(camcorder),
|
|
SEC_BATTERY_ATTR(data_call),
|
|
SEC_BATTERY_ATTR(wifi),
|
|
SEC_BATTERY_ATTR(wibro),
|
|
SEC_BATTERY_ATTR(lte),
|
|
SEC_BATTERY_ATTR(lcd),
|
|
SEC_BATTERY_ATTR(gps),
|
|
SEC_BATTERY_ATTR(event),
|
|
SEC_BATTERY_ATTR(batt_temp_table),
|
|
SEC_BATTERY_ATTR(batt_high_current_usb),
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
SEC_BATTERY_ATTR(test_charge_current),
|
|
#endif
|
|
SEC_BATTERY_ATTR(set_stability_test),
|
|
SEC_BATTERY_ATTR(batt_capacity_max),
|
|
SEC_BATTERY_ATTR(batt_inbat_voltage),
|
|
SEC_BATTERY_ATTR(batt_inbat_voltage_ocv),
|
|
SEC_BATTERY_ATTR(batt_inbat_voltage_adc),
|
|
SEC_BATTERY_ATTR(check_slave_chg),
|
|
SEC_BATTERY_ATTR(batt_inbat_wireless_cs100),
|
|
SEC_BATTERY_ATTR(hmt_ta_connected),
|
|
SEC_BATTERY_ATTR(hmt_ta_charge),
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
SEC_BATTERY_ATTR(fg_cycle),
|
|
SEC_BATTERY_ATTR(fg_full_voltage),
|
|
SEC_BATTERY_ATTR(fg_fullcapnom),
|
|
SEC_BATTERY_ATTR(battery_cycle),
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST_DETACHABLE)
|
|
SEC_BATTERY_ATTR(batt_after_manufactured),
|
|
#endif
|
|
#endif
|
|
SEC_BATTERY_ATTR(fg_cycle_check_value),
|
|
SEC_BATTERY_ATTR(batt_wpc_temp),
|
|
SEC_BATTERY_ATTR(batt_wpc_temp_adc),
|
|
SEC_BATTERY_ATTR(batt_coil_temp), /* Wireless Coil therm */
|
|
SEC_BATTERY_ATTR(batt_coil_temp_adc), /* Wireless Coil therm */
|
|
SEC_BATTERY_ATTR(mst_switch_test), /* MFC MST switch test */
|
|
#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE)
|
|
SEC_BATTERY_ATTR(batt_wireless_firmware_update),
|
|
SEC_BATTERY_ATTR(otp_firmware_result),
|
|
SEC_BATTERY_ATTR(wc_ic_grade),
|
|
SEC_BATTERY_ATTR(otp_firmware_ver_bin),
|
|
SEC_BATTERY_ATTR(otp_firmware_ver),
|
|
SEC_BATTERY_ATTR(tx_firmware_result),
|
|
SEC_BATTERY_ATTR(tx_firmware_ver),
|
|
SEC_BATTERY_ATTR(batt_tx_status),
|
|
#endif
|
|
SEC_BATTERY_ATTR(wc_vout),
|
|
SEC_BATTERY_ATTR(wc_vrect),
|
|
SEC_BATTERY_ATTR(batt_hv_wireless_status),
|
|
SEC_BATTERY_ATTR(batt_hv_wireless_pad_ctrl),
|
|
SEC_BATTERY_ATTR(wc_op_freq),
|
|
SEC_BATTERY_ATTR(wc_cmd_info),
|
|
SEC_BATTERY_ATTR(batt_tune_float_voltage),
|
|
SEC_BATTERY_ATTR(batt_tune_input_charge_current),
|
|
SEC_BATTERY_ATTR(batt_tune_fast_charge_current),
|
|
SEC_BATTERY_ATTR(batt_tune_ui_term_cur_1st),
|
|
SEC_BATTERY_ATTR(batt_tune_ui_term_cur_2nd),
|
|
SEC_BATTERY_ATTR(batt_tune_temp_high_normal),
|
|
SEC_BATTERY_ATTR(batt_tune_temp_high_rec_normal),
|
|
SEC_BATTERY_ATTR(batt_tune_temp_low_normal),
|
|
SEC_BATTERY_ATTR(batt_tune_temp_low_rec_normal),
|
|
SEC_BATTERY_ATTR(batt_tune_chg_temp_high),
|
|
SEC_BATTERY_ATTR(batt_tune_chg_temp_rec),
|
|
SEC_BATTERY_ATTR(batt_tune_chg_limit_cur),
|
|
SEC_BATTERY_ATTR(batt_tune_coil_temp_high),
|
|
SEC_BATTERY_ATTR(batt_tune_coil_temp_rec),
|
|
SEC_BATTERY_ATTR(batt_tune_coil_limit_cur),
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
SEC_BATTERY_ATTR(batt_update_data),
|
|
#endif
|
|
SEC_BATTERY_ATTR(batt_misc_event),
|
|
SEC_BATTERY_ATTR(batt_ext_dev_chg),
|
|
SEC_BATTERY_ATTR(batt_wdt_control),
|
|
SEC_BATTERY_ATTR(mode),
|
|
SEC_BATTERY_ATTR(check_ps_ready),
|
|
SEC_BATTERY_ATTR(batt_chip_id),
|
|
SEC_BATTERY_ATTR(cisd_fullcaprep_max),
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
SEC_BATTERY_ATTR(cisd_data),
|
|
SEC_BATTERY_ATTR(cisd_data_json),
|
|
SEC_BATTERY_ATTR(cisd_data_d_json),
|
|
SEC_BATTERY_ATTR(cisd_wire_count),
|
|
SEC_BATTERY_ATTR(cisd_wc_data),
|
|
SEC_BATTERY_ATTR(cisd_wc_data_json),
|
|
#endif
|
|
SEC_BATTERY_ATTR(safety_timer_set),
|
|
SEC_BATTERY_ATTR(batt_swelling_control),
|
|
SEC_BATTERY_ATTR(safety_timer_info),
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
SEC_BATTERY_ATTR(batt_temp_test),
|
|
#endif
|
|
SEC_BATTERY_ATTR(batt_current_event),
|
|
SEC_BATTERY_ATTR(factory_mode_relieve),
|
|
SEC_BATTERY_ATTR(factory_mode_bypass),
|
|
SEC_BATTERY_ATTR(normal_mode_bypass),
|
|
SEC_BATTERY_ATTR(factory_voltage_regulation),
|
|
SEC_BATTERY_ATTR(factory_mode_disable),
|
|
};
|
|
|
|
static enum power_supply_property sec_battery_props[] = {
|
|
POWER_SUPPLY_PROP_STATUS,
|
|
POWER_SUPPLY_PROP_CHARGE_TYPE,
|
|
POWER_SUPPLY_PROP_HEALTH,
|
|
POWER_SUPPLY_PROP_PRESENT,
|
|
POWER_SUPPLY_PROP_ONLINE,
|
|
POWER_SUPPLY_PROP_TECHNOLOGY,
|
|
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
|
POWER_SUPPLY_PROP_VOLTAGE_AVG,
|
|
POWER_SUPPLY_PROP_CURRENT_NOW,
|
|
POWER_SUPPLY_PROP_CURRENT_AVG,
|
|
POWER_SUPPLY_PROP_CHARGE_FULL,
|
|
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
|
POWER_SUPPLY_PROP_CHARGE_NOW,
|
|
POWER_SUPPLY_PROP_CAPACITY,
|
|
POWER_SUPPLY_PROP_TEMP,
|
|
POWER_SUPPLY_PROP_TEMP_AMBIENT,
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
|
#endif
|
|
POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
|
|
POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL,
|
|
};
|
|
|
|
static enum power_supply_property sec_power_props[] = {
|
|
POWER_SUPPLY_PROP_ONLINE,
|
|
};
|
|
|
|
static enum power_supply_property sec_wireless_props[] = {
|
|
POWER_SUPPLY_PROP_ONLINE,
|
|
POWER_SUPPLY_PROP_PRESENT,
|
|
};
|
|
|
|
static enum power_supply_property sec_ac_props[] = {
|
|
POWER_SUPPLY_PROP_ONLINE,
|
|
POWER_SUPPLY_PROP_TEMP,
|
|
};
|
|
|
|
static enum power_supply_property sec_ps_props[] = {
|
|
POWER_SUPPLY_PROP_STATUS,
|
|
POWER_SUPPLY_PROP_ONLINE,
|
|
};
|
|
|
|
static char *supply_list[] = {
|
|
"battery",
|
|
};
|
|
|
|
char *sec_cable_type[SEC_BATTERY_CABLE_MAX] = {
|
|
"UNKNOWN", /* 0 */
|
|
"NONE", /* 1 */
|
|
"PREPARE_TA", /* 2 */
|
|
"TA", /* 3 */
|
|
"USB", /* 4 */
|
|
"USB_CDP", /* 5 */
|
|
"9V_TA", /* 6 */
|
|
"9V_ERR", /* 7 */
|
|
"9V_UNKNOWN", /* 8 */
|
|
"12V_TA", /* 9 */
|
|
"WIRELESS", /* 10 */
|
|
"HV_WIRELESS", /* 11 */
|
|
"PMA_WIRELESS", /* 12 */
|
|
"WIRELESS_PACK", /* 13 */
|
|
"WIRELESS_PACK_TA", /* 14 */
|
|
"WIRELESS_STAND", /* 15 */
|
|
"WIRELESS_HV_STAND", /* 16 */
|
|
"OC20", /* 17 */
|
|
"QC30", /* 18 */
|
|
"PDIC", /* 19 */
|
|
"UARTOFF", /* 20 */
|
|
"OTG", /* 21 */
|
|
"LAN_HUB", /* 22 */
|
|
"POWER_SHARGING", /* 23 */
|
|
"HMT_CONNECTED", /* 24 */
|
|
"HMT_CHARGE", /* 25 */
|
|
"HV_TA_CHG_LIMIT", /* 26 */
|
|
"WIRELESS_VEHICLE", /* 27 */
|
|
"WIRELESS_HV_VEHICLE", /* 28 */
|
|
"WIRELESS_HV_PREPARE", /* 29 */
|
|
"TIMEOUT", /* 30 */
|
|
"SMART_OTG", /* 31 */
|
|
"SMART_NOTG" /* 32 */
|
|
"FACTORY_UART" /* 33 */
|
|
};
|
|
|
|
char *sec_bat_charging_mode_str[] = {
|
|
"None",
|
|
"Normal",
|
|
"Additional",
|
|
"Re-Charging",
|
|
"ABS"
|
|
};
|
|
|
|
char *sec_bat_status_str[] = {
|
|
"Unknown",
|
|
"Charging",
|
|
"Discharging",
|
|
"Not-charging",
|
|
"Full"
|
|
};
|
|
|
|
char *sec_bat_health_str[] = {
|
|
"Unknown",
|
|
"Good",
|
|
"Overheat",
|
|
"Warm",
|
|
"Dead",
|
|
"OverVoltage",
|
|
"UnspecFailure",
|
|
"Cold",
|
|
"Cool",
|
|
"WatchdogTimerExpire",
|
|
"SafetyTimerExpire",
|
|
"UnderVoltage",
|
|
"OverheatLimit",
|
|
"VsysOVP",
|
|
"VbatOVP",
|
|
};
|
|
|
|
static void sec_bat_set_misc_event(struct sec_battery_info *battery,
|
|
const int misc_event_type, bool do_clear)
|
|
{
|
|
|
|
mutex_lock(&battery->misclock);
|
|
pr_info("%s: %s misc event(now=0x%x, value=0x%x)\n",
|
|
__func__, ((do_clear) ? "clear" : "set"), battery->misc_event, misc_event_type);
|
|
if (do_clear) {
|
|
battery->misc_event &= ~misc_event_type;
|
|
} else {
|
|
battery->misc_event |= misc_event_type;
|
|
}
|
|
mutex_unlock(&battery->misclock);
|
|
|
|
if (battery->prev_misc_event != battery->misc_event) {
|
|
cancel_delayed_work(&battery->misc_event_work);
|
|
wake_lock(&battery->misc_event_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->misc_event_work, 0);
|
|
}
|
|
}
|
|
|
|
static void sec_bat_set_current_event(struct sec_battery_info *battery,
|
|
unsigned int current_event_val, unsigned int current_event_mask)
|
|
{
|
|
unsigned int temp = battery->current_event;
|
|
|
|
mutex_lock(&battery->current_eventlock);
|
|
|
|
battery->current_event &= ~current_event_mask;
|
|
battery->current_event |= current_event_val;
|
|
|
|
pr_info("%s: current event before(0x%x), after(0x%x)\n",
|
|
__func__, temp, battery->current_event);
|
|
|
|
mutex_unlock(&battery->current_eventlock);
|
|
}
|
|
|
|
static void sec_bat_change_default_current(struct sec_battery_info *battery,
|
|
int cable_type, int input, int output)
|
|
{
|
|
battery->pdata->charging_current[cable_type].input_current_limit = input;
|
|
battery->pdata->charging_current[cable_type].fast_charging_current = output;
|
|
pr_info("%s: cable_type: %d input: %d output: %d\n",__func__, cable_type, input, output);
|
|
}
|
|
|
|
static int sec_bat_get_wireless_current(struct sec_battery_info *battery, int incurr)
|
|
{
|
|
/* 1. SIOP EVENT */
|
|
if (battery->siop_event & SIOP_EVENT_WPC_CALL &&
|
|
(battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK_TA)) {
|
|
if (battery->capacity >= battery->pdata->wireless_cc_cv) {
|
|
if (incurr > battery->pdata->siop_call_cv_current)
|
|
incurr = battery->pdata->siop_call_cv_current;
|
|
} else {
|
|
if (incurr > battery->pdata->siop_call_cc_current)
|
|
incurr = battery->pdata->siop_call_cc_current;
|
|
}
|
|
}
|
|
|
|
/* 2. WPC_SLEEP_MODE */
|
|
if (is_hv_wireless_type(battery->cable_type) && sleep_mode) {
|
|
if (incurr > battery->pdata->sleep_mode_limit_current)
|
|
incurr = battery->pdata->sleep_mode_limit_current;
|
|
pr_info("%s sleep_mode =%d, chg_limit =%d, in_curr = %d\n", __func__,
|
|
sleep_mode, battery->chg_limit, incurr);
|
|
}
|
|
|
|
/* 3. WPC_TEMP_MODE */
|
|
if (is_wireless_type(battery->cable_type) && battery->chg_limit) {
|
|
if ((battery->siop_level >= 100) &&
|
|
(incurr > battery->pdata->wpc_charging_limit_current))
|
|
incurr = battery->pdata->wpc_charging_limit_current;
|
|
else if ((battery->siop_level < 100) &&
|
|
(incurr > battery->pdata->wpc_lcd_on_charging_limit_current))
|
|
incurr = battery->pdata->wpc_lcd_on_charging_limit_current;
|
|
}
|
|
|
|
/* 4. WPC_CV_MODE */
|
|
if (battery->wc_cv_mode) {
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_STAND ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK_TA) {
|
|
if (incurr > battery->pdata->wc_cv_current)
|
|
incurr = battery->pdata->wc_cv_current;
|
|
} else if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK) {
|
|
if (incurr > battery->pdata->wc_cv_pack_current)
|
|
incurr = battery->pdata->wc_cv_pack_current;
|
|
}
|
|
}
|
|
|
|
/* 5. Full-Additional state */
|
|
if (battery->status == POWER_SUPPLY_STATUS_FULL && battery->charging_mode == SEC_BATTERY_CHARGING_2ND) {
|
|
if (incurr > battery->pdata->siop_hv_wireless_input_limit_current)
|
|
incurr = battery->pdata->siop_hv_wireless_input_limit_current;
|
|
}
|
|
|
|
/* 6. Hero Stand Pad CV */
|
|
if (battery->capacity >= battery->pdata->wc_hero_stand_cc_cv) {
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_STAND) {
|
|
if (incurr > battery->pdata->wc_hero_stand_cv_current)
|
|
incurr = battery->pdata->wc_hero_stand_cv_current;
|
|
} else if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_HV_STAND) {
|
|
if (incurr > battery->pdata->wc_hero_stand_hv_cv_current)
|
|
incurr = battery->pdata->wc_hero_stand_hv_cv_current;
|
|
}
|
|
}
|
|
|
|
/* 7. Full-None state && SIOP_LEVEL 100 */
|
|
if (battery->siop_level == 100 &&
|
|
battery->status == POWER_SUPPLY_STATUS_FULL && battery->charging_mode == SEC_BATTERY_CHARGING_NONE) {
|
|
incurr = battery->pdata->wc_full_input_limit_current;
|
|
}
|
|
|
|
return incurr;
|
|
}
|
|
|
|
static void sec_bat_get_charging_current_by_siop(struct sec_battery_info *battery,
|
|
int *input_current, int *charging_current)
|
|
{
|
|
if (battery->pdata->siop_default_power > 0) {
|
|
if ((battery->max_charge_power > battery->pdata->siop_default_power) &&
|
|
(battery->siop_level < 100)) {
|
|
*charging_current = *charging_current * battery->siop_level / 100;
|
|
}
|
|
} else if (battery->siop_level == 3) {
|
|
/* side sync scenario : siop_level 3 */
|
|
if (is_nv_wireless_type(battery->cable_type)) {
|
|
if (*input_current > battery->pdata->siop_wireless_input_limit_current)
|
|
*input_current = battery->pdata->siop_wireless_input_limit_current;
|
|
*charging_current = battery->pdata->siop_wireless_charging_limit_current;
|
|
} else if (is_hv_wireless_type(battery->cable_type)) {
|
|
if (*input_current > battery->pdata->siop_hv_wireless_input_limit_current)
|
|
*input_current = battery->pdata->siop_hv_wireless_input_limit_current;
|
|
*charging_current = battery->pdata->siop_hv_wireless_charging_limit_current;
|
|
} else if (is_hv_wire_type(battery->cable_type)) {
|
|
if (*input_current > 450)
|
|
*input_current = 450;
|
|
*charging_current = battery->pdata->siop_hv_charging_limit_current;
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
} else if (is_pd_wire_type(battery->cable_type)) {
|
|
if (*input_current > (4000 / battery->input_voltage))
|
|
*input_current = 4000 / battery->input_voltage;
|
|
*charging_current = battery->pdata->siop_hv_charging_limit_current;
|
|
#endif
|
|
} else {
|
|
if (*input_current > 800)
|
|
*input_current = 800;
|
|
*charging_current = battery->pdata->charging_current[
|
|
battery->cable_type].fast_charging_current;
|
|
if (*charging_current > battery->pdata->siop_charging_limit_current)
|
|
*charging_current = battery->pdata->siop_charging_limit_current;
|
|
}
|
|
} else if (battery->siop_level == 5) {
|
|
/* special senario : calling or browsing during wired charging */
|
|
if (is_hv_wire_type(battery->cable_type) &&
|
|
!(battery->current_event & SEC_BAT_CURRENT_EVENT_CHG_LIMIT)) {
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_12V_TA)
|
|
*input_current = 440;
|
|
else
|
|
*input_current = 600;
|
|
*charging_current = 900;
|
|
} else if (battery->cable_type == SEC_BATTERY_CABLE_TA ||
|
|
(battery->current_event & SEC_BAT_CURRENT_EVENT_CHG_LIMIT)) {
|
|
if(battery->pdata->charging_current_browsing_mode > 0){
|
|
*input_current = battery->pdata->siop_input_limit_current;
|
|
*charging_current = battery->pdata->charging_current_browsing_mode;
|
|
} else {
|
|
*input_current = 1000;
|
|
*charging_current = 900;
|
|
}
|
|
}
|
|
} else if (battery->siop_level < 100) {
|
|
int max_charging_current;
|
|
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
max_charging_current = 1000; /* 1 step(70) */
|
|
if (battery->siop_level == 0) { /* 3 step(0) */
|
|
max_charging_current = 0;
|
|
} else if (battery->siop_level <= 10) { /* 2 step(10) */
|
|
max_charging_current = 500;
|
|
}
|
|
} else {
|
|
max_charging_current = 1800; /* 1 step(70) */
|
|
|
|
/* if siop level is 0, set minimum charging current from dt */
|
|
if (battery->siop_level == 0 &&
|
|
battery->pdata->minimum_charging_current_by_siop_0 > 0){
|
|
pr_info("%s: charging current(%d) when siop level is 0\n",
|
|
__func__, battery->pdata->minimum_charging_current_by_siop_0);
|
|
*charging_current = battery->pdata->minimum_charging_current_by_siop_0;
|
|
}
|
|
}
|
|
|
|
/* do forced set charging current */
|
|
if (*charging_current > max_charging_current)
|
|
*charging_current = max_charging_current;
|
|
|
|
if (is_nv_wireless_type(battery->cable_type)) {
|
|
if (*input_current > battery->pdata->siop_wireless_input_limit_current)
|
|
*input_current = battery->pdata->siop_wireless_input_limit_current;
|
|
if (*charging_current > battery->pdata->siop_wireless_charging_limit_current)
|
|
*charging_current = battery->pdata->siop_wireless_charging_limit_current;
|
|
} else if (is_hv_wireless_type(battery->cable_type)) {
|
|
if (*input_current > battery->pdata->siop_hv_wireless_input_limit_current)
|
|
*input_current = battery->pdata->siop_hv_wireless_input_limit_current;
|
|
if (*charging_current > battery->pdata->siop_hv_wireless_charging_limit_current)
|
|
*charging_current = battery->pdata->siop_hv_wireless_charging_limit_current;
|
|
} else if (is_hv_wire_type(battery->cable_type) &&
|
|
is_hv_wire_type(battery->wire_status)) {
|
|
if (is_hv_wire_12v_type(battery->cable_type)) {
|
|
if (*input_current > battery->pdata->siop_hv_12v_input_limit_current)
|
|
*input_current = battery->pdata->siop_hv_12v_input_limit_current;
|
|
} else {
|
|
if(battery->siop_level == 20 && battery->pdata->input_current_by_siop_20 > 0)
|
|
*input_current = battery->pdata->input_current_by_siop_20;
|
|
else if(battery->siop_level == 40 && battery->pdata->input_current_by_siop_40 > 0)
|
|
*input_current = battery->pdata->input_current_by_siop_40;
|
|
else if (*input_current > battery->pdata->siop_hv_input_limit_current)
|
|
*input_current = battery->pdata->siop_hv_input_limit_current;
|
|
}
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
} else if (is_pd_wire_type(battery->cable_type)) {
|
|
if (*input_current > (6000 / battery->input_voltage))
|
|
*input_current = 6000 / battery->input_voltage;
|
|
#endif
|
|
} else {
|
|
if (*input_current > battery->pdata->siop_input_limit_current)
|
|
*input_current = battery->pdata->siop_input_limit_current;
|
|
}
|
|
}
|
|
|
|
pr_info("%s: incurr(%d), chgcurr(%d)\n", __func__, *input_current, *charging_current);
|
|
}
|
|
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
static int sec_bat_get_temp_by_temp_control_source(struct sec_battery_info *battery,
|
|
enum sec_battery_temp_control_source tcs)
|
|
{
|
|
switch (tcs) {
|
|
case TEMP_CONTROL_SOURCE_CHG_THM:
|
|
return battery->chg_temp;
|
|
case TEMP_CONTROL_SOURCE_USB_THM:
|
|
return battery->usb_temp;
|
|
case TEMP_CONTROL_SOURCE_WPC_THM:
|
|
return battery->wpc_temp;
|
|
case TEMP_CONTROL_SOURCE_NONE:
|
|
case TEMP_CONTROL_SOURCE_BAT_THM:
|
|
default:
|
|
return battery->temperature;
|
|
}
|
|
}
|
|
|
|
static void sec_bat_check_mix_temp(struct sec_battery_info *battery, int *input_current, int *charging_current)
|
|
{
|
|
if (battery->pdata->chg_temp_check && battery->siop_level >= 100 && is_not_wireless_type(battery->cable_type)) {
|
|
if ((!battery->mix_limit &&
|
|
(battery->temperature > battery->pdata->mix_high_temp) &&
|
|
(battery->chg_temp > battery->pdata->mix_high_chg_temp)) ||
|
|
(battery->mix_limit &&
|
|
(battery->temperature >= battery->pdata->mix_high_temp_recovery) &&
|
|
(battery->pdata->mix_high_temp_recovery > 0)) ||
|
|
(battery->mix_limit &&
|
|
(battery->chg_temp >= battery->pdata->mix_high_chg_temp_recovery) &&
|
|
(battery->pdata->mix_high_chg_temp_recovery > 0))) {
|
|
int max_input_current =
|
|
battery->pdata->full_check_current_1st + 50;
|
|
|
|
/* input current = float voltage * (topoff_current_1st + 50mA(margin)) / (vbus_level * 0.9) */
|
|
if (battery->pdata->mix_temp_input_current > 0)
|
|
*input_current = battery->pdata->mix_temp_input_current;
|
|
else
|
|
*input_current = ((battery->pdata->chg_float_voltage / battery->pdata->chg_float_voltage_conv) * max_input_current) /
|
|
(battery->input_voltage * 90) / 10;
|
|
|
|
/*set_charging current*/
|
|
if (battery->pdata->mix_temp_charging_current > 0)
|
|
*charging_current = (*charging_current > battery->pdata->mix_temp_charging_current) ?
|
|
battery->pdata->mix_temp_charging_current : *charging_current;
|
|
|
|
battery->mix_limit = true;
|
|
/* skip other heating control */
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL,
|
|
SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL);
|
|
} else if (battery->mix_limit) {
|
|
battery->mix_limit = false;
|
|
}
|
|
|
|
pr_info("%s: mix_limit(%d), temp(%d), chg_temp(%d), input_current(%d), charging_current(%d)\n",
|
|
__func__, battery->mix_limit, battery->temperature, battery->chg_temp, *input_current, *charging_current);
|
|
} else {
|
|
battery->mix_limit = false;
|
|
}
|
|
}
|
|
|
|
static int sec_bat_check_wpc_temp(struct sec_battery_info *battery, int input_current)
|
|
{
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
int wpc_vout_level = WIRELESS_VOUT_10V;
|
|
|
|
if (battery->siop_level >= 100) {
|
|
int temp_val = sec_bat_get_temp_by_temp_control_source(battery,
|
|
battery->pdata->wpc_temp_control_source);
|
|
|
|
if ((!battery->chg_limit && temp_val > battery->pdata->wpc_high_temp) ||
|
|
(battery->chg_limit && temp_val > battery->pdata->wpc_high_temp_recovery)) {
|
|
battery->chg_limit = true;
|
|
input_current = battery->pdata->wpc_charging_limit_current;
|
|
wpc_vout_level = WIRELESS_VOUT_5V_STEP;
|
|
} else if (battery->chg_limit) {
|
|
battery->chg_limit = false;
|
|
}
|
|
} else {
|
|
if (is_hv_wireless_type(battery->cable_type) ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_PREPARE_WIRELESS_HV) {
|
|
if (battery->cable_type != SEC_BATTERY_CABLE_WIRELESS_HV_VEHICLE) {
|
|
if ((!battery->chg_limit &&
|
|
battery->chg_temp > battery->pdata->wpc_lcd_on_high_temp) ||
|
|
(battery->chg_limit &&
|
|
battery->chg_temp >= battery->pdata->wpc_lcd_on_high_temp_rec)) {
|
|
input_current = battery->pdata->wpc_lcd_on_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
wpc_vout_level = (battery->capacity < 95) ?
|
|
WIRELESS_VOUT_5V_STEP : WIRELESS_VOUT_10V;
|
|
} else if (battery->chg_limit) {
|
|
battery->chg_limit = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_hv_wireless_type(battery->cable_type)) {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_SWELLING_MODE)
|
|
wpc_vout_level = WIRELESS_VOUT_5V_STEP;
|
|
|
|
if (wpc_vout_level != battery->wpc_vout_level) {
|
|
battery->wpc_vout_level = wpc_vout_level;
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_WPC_VOUT_LOCK) {
|
|
pr_info("%s: block to set wpc vout level(%d) because otg on\n",
|
|
__func__, wpc_vout_level);
|
|
} else {
|
|
union power_supply_propval value = {0, };
|
|
|
|
value.intval = wpc_vout_level;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
pr_info("%s: change vout level(%d)",
|
|
__func__, battery->wpc_vout_level);
|
|
}
|
|
}
|
|
}
|
|
pr_info("%s: change input_current(%d), vout_level(%d), chg_limit(%d)\n",
|
|
__func__, input_current, battery->wpc_vout_level, battery->chg_limit);
|
|
}
|
|
|
|
return input_current;
|
|
}
|
|
|
|
#if defined(CONFIG_HV_MUIC_VOLTAGE_CTRL) || defined(CONFIG_SUPPORT_QC30)
|
|
extern int muic_afc_set_voltage(int vol);
|
|
#endif
|
|
static void sec_bat_check_afc_temp(struct sec_battery_info *battery, int *input_current, int *charging_current)
|
|
{
|
|
#if defined(CONFIG_HV_MUIC_VOLTAGE_CTRL) || defined(CONFIG_SUPPORT_QC30)
|
|
if (battery->siop_level >= 100) {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_CHG_LIMIT) {
|
|
battery->chg_limit = battery->vbus_chg_by_siop = false;
|
|
*input_current = battery->pdata->pre_afc_input_current;
|
|
{
|
|
/* change input current */
|
|
union power_supply_propval value;
|
|
battery->charge_power = battery->input_voltage * (*input_current);
|
|
value.intval = *input_current;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
battery->input_current = *input_current;
|
|
}
|
|
/* set current event */
|
|
cancel_delayed_work(&battery->afc_work);
|
|
wake_unlock(&battery->afc_wake_lock);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_AFC,
|
|
(SEC_BAT_CURRENT_EVENT_CHG_LIMIT | SEC_BAT_CURRENT_EVENT_AFC));
|
|
/* vbus level : 5V --> 9V */
|
|
if (battery->chg_limit_recovery_cable == SEC_BATTERY_CABLE_12V_TA) {
|
|
muic_afc_set_voltage(SEC_INPUT_VOLTAGE_12V);
|
|
} else {
|
|
muic_afc_set_voltage(SEC_INPUT_VOLTAGE_9V);
|
|
}
|
|
} else if (!battery->chg_limit && is_hv_wire_type(battery->cable_type) && (battery->chg_temp > battery->pdata->chg_high_temp)) {
|
|
*input_current = battery->pdata->chg_input_limit_current;
|
|
*charging_current = battery->pdata->chg_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
} else if (!battery->chg_limit && battery->max_charge_power >= (battery->pdata->pd_charging_charge_power - 500) && (battery->chg_temp > battery->pdata->chg_high_temp)) {
|
|
*input_current = battery->pdata->default_ta_input_current;
|
|
*charging_current = battery->pdata->default_ta_output_current;
|
|
battery->chg_limit = true;
|
|
} else if (battery->chg_limit && is_hv_wire_type(battery->cable_type)) {
|
|
if (battery->chg_temp < battery->pdata->chg_high_temp_recovery) {
|
|
*input_current = battery->pdata->charging_current[battery->cable_type].input_current_limit;
|
|
*charging_current = battery->pdata->charging_current[battery->cable_type].fast_charging_current;
|
|
battery->chg_limit = false;
|
|
} else {
|
|
*input_current = battery->pdata->chg_input_limit_current;
|
|
*charging_current = battery->pdata->chg_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
}
|
|
} else if (battery->chg_limit && battery->max_charge_power >= (battery->pdata->pd_charging_charge_power - 500)) {
|
|
if (battery->chg_temp < battery->pdata->chg_high_temp_recovery) {
|
|
*input_current = battery->pdata->charging_current[battery->cable_type].input_current_limit;
|
|
*charging_current = battery->pdata->charging_current[battery->cable_type].fast_charging_current;
|
|
battery->chg_limit = false;
|
|
} else {
|
|
*input_current = battery->pdata->chg_input_limit_current;
|
|
*charging_current = battery->pdata->chg_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
}
|
|
}
|
|
pr_info("%s: cable_type(%d), chg_limit(%d) vbus_by_siop(%d)\n", __func__,
|
|
battery->cable_type, battery->chg_limit, battery->vbus_chg_by_siop);
|
|
} else if (is_hv_wire_type(battery->cable_type) && is_hv_wire_type(battery->wire_status) &&
|
|
!battery->store_mode && (battery->cable_type != SEC_BATTERY_CABLE_QC30) &&
|
|
(battery->status == POWER_SUPPLY_STATUS_CHARGING) && !battery->vbus_chg_by_siop) {
|
|
battery->chg_limit_recovery_cable = battery->cable_type;
|
|
battery->vbus_chg_by_siop = true;
|
|
battery->chg_limit = false;
|
|
/* vbus level : 9V --> 5V */
|
|
muic_afc_set_voltage(SEC_INPUT_VOLTAGE_5V);
|
|
pr_info("%s: vbus set 5V by siop(recovery cable: %d)\n", __func__,battery->chg_limit_recovery_cable);
|
|
}
|
|
#else
|
|
if (is_hv_wire_type(battery->cable_type)) {
|
|
if ((!battery->chg_limit && (battery->chg_temp > battery->pdata->chg_high_temp)) ||
|
|
(battery->chg_limit && (battery->chg_temp >= battery->pdata->chg_high_temp_recovery))) {
|
|
*input_current = battery->pdata->chg_input_limit_current;
|
|
*charging_current = battery->pdata->chg_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
} else if (battery->chg_limit)
|
|
battery->chg_limit = false;
|
|
|
|
pr_info("%s: chg_limit(%d), input_current(%d), charging_current(%d)\n",
|
|
__func__, battery->chg_limit, *input_current, *charging_current);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void sec_bat_chg_temperature_check(struct sec_battery_info *battery,
|
|
int *input_current, int *charging_current)
|
|
{
|
|
if ((battery->siop_level >= 100) &&
|
|
is_hv_wire_type(battery->cable_type)) {
|
|
if (!battery->chg_limit &&
|
|
(battery->chg_temp > battery->pdata->chg_high_temp)) {
|
|
battery->chg_limit = true;
|
|
*input_current = battery->pdata->chg_input_limit_current;
|
|
*charging_current = battery->pdata->chg_charging_limit_current;
|
|
dev_info(battery->dev,"%s: Chg current is reduced by Temp: %d\n",
|
|
__func__, battery->chg_temp);
|
|
} else if (battery->chg_limit &&
|
|
(battery->chg_temp < battery->pdata->chg_high_temp_recovery)) {
|
|
battery->chg_limit = false;
|
|
*input_current = battery->pdata->charging_current
|
|
[battery->cable_type].input_current_limit;
|
|
*charging_current = battery->pdata->charging_current
|
|
[battery->cable_type].fast_charging_current;
|
|
dev_info(battery->dev,"%s: Chg current is recovered by Temp: %d\n",
|
|
__func__, battery->chg_temp);
|
|
} else if (battery->chg_limit &&
|
|
(battery->chg_temp > battery->pdata->chg_high_temp)) {
|
|
*input_current = battery->pdata->chg_input_limit_current;
|
|
*charging_current = battery->pdata->chg_charging_limit_current;
|
|
}
|
|
}
|
|
pr_info("%s: cable_type(%d), chg_limit(%d)\n", __func__,
|
|
battery->cable_type, battery->chg_limit);
|
|
}
|
|
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
extern void select_pdo(int num);
|
|
static bool sec_bat_change_vbus_pd(struct sec_battery_info *battery, int *input_current)
|
|
{
|
|
#if defined(CONFIG_HV_MUIC_VOLTAGE_CTRL)
|
|
unsigned int target_pd_index = 0;
|
|
|
|
if (battery->store_mode)
|
|
return false;
|
|
|
|
if (is_pd_wire_type(battery->cable_type)) {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_SELECT_PDO) {
|
|
pr_info("%s: skip during current_event(0x%x)\n",
|
|
__func__, battery->current_event);
|
|
return false;
|
|
}
|
|
|
|
if (battery->siop_level >= 100) {
|
|
/* select PDO greater than 5V */
|
|
target_pd_index = battery->pd_list.max_pd_count - 1;
|
|
} else {
|
|
/* select 5V PDO */
|
|
target_pd_index = 0;
|
|
}
|
|
pr_info("%s: target_pd_index: %d, now_pd_index: %d\n", __func__,
|
|
target_pd_index, battery->pd_list.now_pd_index);
|
|
|
|
if (target_pd_index != battery->pd_list.now_pd_index) {
|
|
/* change input current before request new pdo if new pdo's input current is less than now */
|
|
if (battery->pd_list.pd_info[target_pd_index].input_current < battery->input_current) {
|
|
union power_supply_propval value = {0, };
|
|
|
|
*input_current = battery->pd_list.pd_info[target_pd_index].input_current;
|
|
value.intval = *input_current;
|
|
battery->input_current = *input_current;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SELECT_PDO,
|
|
SEC_BAT_CURRENT_EVENT_SELECT_PDO);
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
}
|
|
battery->pdic_ps_rdy = false;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SELECT_PDO,
|
|
SEC_BAT_CURRENT_EVENT_SELECT_PDO);
|
|
battery->pdic_info.sink_status.selected_pdo_num =
|
|
battery->pd_list.pd_info[target_pd_index].pdo_index;
|
|
select_pdo(battery->pd_list.pd_info[target_pd_index].pdo_index);
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
static void sec_bat_check_pdic_temp(struct sec_battery_info *battery, int *input_current, int *charging_current)
|
|
{
|
|
if (battery->pdic_ps_rdy && battery->siop_level >= 100 && !battery->lcd_status) {
|
|
if ((!battery->chg_limit && (battery->chg_temp >= battery->pdata->chg_high_temp)) ||
|
|
(battery->chg_limit && (battery->chg_temp >= battery->pdata->chg_high_temp_recovery))) {
|
|
*input_current =
|
|
(battery->pdata->chg_input_limit_current * SEC_INPUT_VOLTAGE_9V) / battery->input_voltage;
|
|
*charging_current = battery->pdata->chg_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
} else if (battery->chg_limit && battery->chg_temp <= battery->pdata->chg_high_temp_recovery) {
|
|
*input_current = battery->pdata->charging_current[battery->cable_type].input_current_limit;
|
|
*charging_current = battery->pdata->charging_current[battery->cable_type].fast_charging_current;
|
|
battery->chg_limit = false;
|
|
}
|
|
pr_info("%s: cable_type(%d), chg_limit(%d)\n", __func__,
|
|
battery->cable_type, battery->chg_limit);
|
|
}
|
|
}
|
|
|
|
static int sec_bat_check_pd_input_current(struct sec_battery_info *battery, int input_current)
|
|
{
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_SELECT_PDO) {
|
|
input_current = battery->input_current;
|
|
pr_info("%s: change input_current(%d), cable_type(%d)\n", __func__, input_current, battery->cable_type);
|
|
}
|
|
|
|
return input_current;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
static int sec_bat_check_afc_input_current(struct sec_battery_info *battery, int input_current)
|
|
{
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_AFC) {
|
|
int work_delay = 0;
|
|
|
|
if (!is_wireless_type(battery->cable_type)) {
|
|
input_current = battery->pdata->pre_afc_input_current; // 1000mA
|
|
work_delay = battery->pdata->pre_afc_work_delay;
|
|
} else {
|
|
input_current = battery->pdata->pre_wc_afc_input_current;
|
|
/* do not reduce this time, this is for noble pad */
|
|
work_delay = battery->pdata->pre_wc_afc_work_delay;
|
|
}
|
|
|
|
wake_lock(&battery->afc_wake_lock);
|
|
if (!delayed_work_pending(&battery->afc_work))
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->afc_work, msecs_to_jiffies(work_delay));
|
|
|
|
pr_info("%s: change input_current(%d), cable_type(%d)\n", __func__, input_current, battery->cable_type);
|
|
}
|
|
|
|
return input_current;
|
|
}
|
|
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
static void sec_bat_get_input_current_in_power_list(struct sec_battery_info *battery)
|
|
{
|
|
int pdo_num = battery->pdic_info.sink_status.current_pdo_num;
|
|
int max_input_current = 0;
|
|
|
|
max_input_current = battery->pdata->charging_current[SEC_BATTERY_CABLE_PDIC].input_current_limit =
|
|
battery->pdic_info.sink_status.power_list[pdo_num].max_current;
|
|
|
|
pr_info("%s:max_input_current : %dmA\n", __func__, max_input_current);
|
|
}
|
|
|
|
static void sec_bat_get_charging_current_in_power_list(struct sec_battery_info *battery)
|
|
{
|
|
int max_charging_current = 0;
|
|
int pdo_num = battery->pdic_info.sink_status.current_pdo_num;
|
|
int pd_power = (battery->pdic_info.sink_status.power_list[pdo_num].max_voltage *
|
|
battery->pdic_info.sink_status.power_list[pdo_num].max_current);
|
|
|
|
/* We assume that output voltage to float voltage */
|
|
max_charging_current = pd_power / (battery->pdata->chg_float_voltage / battery->pdata->chg_float_voltage_conv);
|
|
max_charging_current = max_charging_current > battery->pdata->max_charging_current ?
|
|
battery->pdata->max_charging_current : max_charging_current;
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_PDIC].fast_charging_current = max_charging_current;
|
|
battery->charge_power = pd_power;
|
|
|
|
pr_info("%s:pd_charge_power : %dmW, max_charging_current : %dmA\n", __func__,
|
|
battery->charge_power, max_charging_current);
|
|
}
|
|
#endif
|
|
|
|
static int sec_bat_set_charging_current(struct sec_battery_info *battery)
|
|
{
|
|
static int afc_init = false;
|
|
union power_supply_propval value = {0, };
|
|
int input_current = battery->pdata->charging_current[battery->cable_type].input_current_limit,
|
|
charging_current = battery->pdata->charging_current[battery->cable_type].fast_charging_current,
|
|
topoff_current = battery->pdata->full_check_current_1st;
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
int temp = 0;
|
|
#endif
|
|
|
|
if (battery->aicl_current)
|
|
input_current = battery->aicl_current;
|
|
mutex_lock(&battery->iolock);
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE) {
|
|
} else {
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
if (!(battery->current_event & SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL)) {
|
|
sec_bat_check_mix_temp(battery, &input_current, &charging_current);
|
|
}
|
|
#endif
|
|
|
|
/* check input current */
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
if (!(battery->current_event & SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL)) {
|
|
if (battery->pdata->wpc_temp_check) {
|
|
temp = sec_bat_check_wpc_temp(battery, input_current);
|
|
if (input_current > temp)
|
|
input_current = temp;
|
|
}
|
|
|
|
if (battery->pdata->chg_temp_check) {
|
|
switch (battery->pdata->chg_heating_prevention_method) {
|
|
case SEC_BATTERY_BY_CHANGING_VOLTAGE:
|
|
sec_bat_check_afc_temp(battery, &input_current, &charging_current);
|
|
break;
|
|
case SEC_BATTERY_BY_CHANGING_CURRENT:
|
|
sec_bat_chg_temperature_check(battery, &input_current, &charging_current);
|
|
break;
|
|
default:
|
|
sec_bat_check_afc_temp(battery, &input_current, &charging_current);
|
|
break;
|
|
}
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_PDIC) {
|
|
if (!sec_bat_change_vbus_pd(battery, &input_current)) {
|
|
sec_bat_check_pdic_temp(battery, &input_current, &charging_current);
|
|
input_current = sec_bat_check_pd_input_current(battery, input_current);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
input_current = sec_bat_check_afc_input_current(battery, input_current);
|
|
/*
|
|
* Set limited max current with hv wire cable when store mode is set and LDU
|
|
* Limited max current should be set with over 5% capacity since target could be turned off during boot up
|
|
*/
|
|
if (battery->store_mode && is_hv_wire_type(battery->wire_status) && (battery->capacity >= 5)) {
|
|
input_current = battery->pdata->store_mode_afc_input_current;
|
|
}
|
|
|
|
sec_bat_get_charging_current_by_siop(battery, &input_current, &charging_current);
|
|
|
|
/* Calculate wireless input current under the specific conditions (siop_event, wpc_sleep_mode, chg_limit)*/
|
|
if (battery->wc_status != SEC_WIRELESS_PAD_NONE) {
|
|
input_current = sec_bat_get_wireless_current(battery, input_current);
|
|
}
|
|
|
|
/* check topoff current */
|
|
if (battery->charging_mode == SEC_BATTERY_CHARGING_2ND &&
|
|
((battery->pdata->full_check_type_2nd == SEC_BATTERY_FULLCHARGED_CHGPSY) ||
|
|
(battery->pdata->full_check_type_2nd == SEC_BATTERY_FULLCHARGED_FG_CURRENT))) {
|
|
topoff_current =
|
|
battery->pdata->full_check_current_2nd;
|
|
}
|
|
|
|
/* check swelling state */
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND) {
|
|
charging_current = (charging_current > battery->pdata->swelling_wc_low_temp_current_2nd) ?
|
|
battery->pdata->swelling_wc_low_temp_current_2nd : charging_current;
|
|
topoff_current = (topoff_current > battery->pdata->swelling_low_temp_topoff) ?
|
|
battery->pdata->swelling_low_temp_topoff : topoff_current;
|
|
} else if (battery->current_event & SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING) {
|
|
charging_current = (charging_current > battery->pdata->swelling_wc_high_temp_current) ?
|
|
battery->pdata->swelling_wc_high_temp_current : charging_current;
|
|
topoff_current = (topoff_current > battery->pdata->swelling_high_temp_topoff) ?
|
|
battery->pdata->swelling_high_temp_topoff : topoff_current;
|
|
} else if (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING) {
|
|
charging_current = (charging_current > battery->pdata->swelling_wc_low_temp_current) ?
|
|
battery->pdata->swelling_wc_low_temp_current : charging_current;
|
|
}
|
|
} else {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND) {
|
|
charging_current = (charging_current > battery->pdata->swelling_low_temp_current_2nd) ?
|
|
battery->pdata->swelling_low_temp_current_2nd : charging_current;
|
|
topoff_current = (topoff_current > battery->pdata->swelling_low_temp_topoff) ?
|
|
battery->pdata->swelling_low_temp_topoff : topoff_current;
|
|
} else if (battery->current_event & SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING) {
|
|
charging_current = (charging_current > battery->pdata->swelling_high_temp_current) ?
|
|
battery->pdata->swelling_high_temp_current : charging_current;
|
|
topoff_current = (topoff_current > battery->pdata->swelling_high_temp_topoff) ?
|
|
battery->pdata->swelling_high_temp_topoff : topoff_current;
|
|
} else if (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING) {
|
|
charging_current = (charging_current > battery->pdata->swelling_low_temp_current) ?
|
|
battery->pdata->swelling_low_temp_current : charging_current;
|
|
}
|
|
|
|
/* usb unconfigured or suspend */
|
|
if ((battery->cable_type == SEC_BATTERY_CABLE_USB) && !lpcharge) {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_USB_100MA) {
|
|
pr_info("%s: usb unconfigured\n", __func__);
|
|
input_current = USB_CURRENT_UNCONFIGURED;
|
|
charging_current = USB_CURRENT_UNCONFIGURED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* In wireless charging, must be set charging current before input current. */
|
|
if (is_wireless_type(battery->cable_type) &&
|
|
battery->charging_current != charging_current) {
|
|
value.intval = charging_current;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_AVG, value);
|
|
battery->charging_current = charging_current;
|
|
}
|
|
/* set input current, charging current */
|
|
if ((battery->input_current != input_current) ||
|
|
(battery->charging_current != charging_current)) {
|
|
/* update charge power */
|
|
battery->charge_power = battery->input_voltage * input_current;
|
|
if (battery->charge_power > battery->max_charge_power) {
|
|
battery->max_charge_power = battery->charge_power;
|
|
}
|
|
|
|
value.intval = input_current;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
battery->input_current = input_current;
|
|
|
|
value.intval = charging_current;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_NOW, value);
|
|
|
|
if (charging_current <= 100)
|
|
battery->charging_current = 100;
|
|
else
|
|
battery->charging_current = charging_current;
|
|
pr_info("%s: power(%d), input(%d), charge(%d)\n", __func__,
|
|
battery->charge_power, battery->input_current, battery->charging_current);
|
|
}
|
|
|
|
/* set topoff current */
|
|
if (battery->topoff_current != topoff_current) {
|
|
value.intval = topoff_current;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_FULL, value);
|
|
battery->topoff_current = topoff_current;
|
|
}
|
|
if (!afc_init) {
|
|
afc_init = true;
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
value.intval = 1;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_AFC_CHARGER_MODE,
|
|
value);
|
|
#endif
|
|
}
|
|
mutex_unlock(&battery->iolock);
|
|
return 0;
|
|
}
|
|
|
|
static int sec_bat_set_charge(
|
|
struct sec_battery_info *battery,
|
|
int chg_mode)
|
|
{
|
|
union power_supply_propval val = {0, };
|
|
ktime_t current_time = {0, };
|
|
struct timespec ts = {0, };
|
|
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_HMT_CONNECTED)
|
|
return 0;
|
|
|
|
if ((battery->current_event & SEC_BAT_CURRENT_EVENT_CHARGE_DISABLE) &&
|
|
(chg_mode == SEC_BAT_CHG_MODE_CHARGING)) {
|
|
dev_info(battery->dev, "%s: charge disable by HMT\n", __func__);
|
|
chg_mode = SEC_BAT_CHG_MODE_CHARGING_OFF;
|
|
}
|
|
|
|
if (battery->misc_event & (BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE | BATT_MISC_EVENT_HICCUP_TYPE))
|
|
chg_mode = SEC_BAT_CHG_MODE_BUCK_OFF;
|
|
|
|
val.intval = battery->status;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_STATUS, val);
|
|
current_time = ktime_get_boottime();
|
|
ts = ktime_to_timespec(current_time);
|
|
|
|
if (chg_mode == SEC_BAT_CHG_MODE_CHARGING) {
|
|
/*Reset charging start time only in initial charging start */
|
|
if (battery->charging_start_time == 0) {
|
|
if (ts.tv_sec < 1)
|
|
ts.tv_sec = 1;
|
|
battery->charging_start_time = ts.tv_sec;
|
|
battery->charging_next_time =
|
|
battery->pdata->charging_reset_time;
|
|
}
|
|
battery->charging_block = false;
|
|
} else {
|
|
battery->charging_start_time = 0;
|
|
battery->charging_passed_time = 0;
|
|
battery->charging_next_time = 0;
|
|
battery->charging_fullcharged_time = 0;
|
|
battery->full_check_cnt = 0;
|
|
battery->charging_block = true;
|
|
#if defined(CONFIG_STEP_CHARGING)
|
|
sec_bat_reset_step_charging(battery);
|
|
#endif
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->usb_overheat_check = false;
|
|
battery->cisd.ab_vbat_check_count = 0;
|
|
if (chg_mode == SEC_BAT_CHG_MODE_BUCK_OFF) {
|
|
battery->cisd.data[CISD_DATA_BUCK_OFF]++;
|
|
battery->cisd.data[CISD_DATA_BUCK_OFF_PER_DAY]++;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
battery->temp_highlimit_cnt = 0;
|
|
battery->temp_high_cnt = 0;
|
|
battery->temp_low_cnt = 0;
|
|
battery->temp_recover_cnt = 0;
|
|
|
|
val.intval = chg_mode;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGING_ENABLED, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool sec_bat_check_by_psy(struct sec_battery_info *battery)
|
|
{
|
|
char *psy_name = NULL;
|
|
union power_supply_propval value = {0, };
|
|
bool ret = true;
|
|
|
|
switch (battery->pdata->battery_check_type) {
|
|
case SEC_BATTERY_CHECK_PMIC:
|
|
psy_name = battery->pdata->pmic_name;
|
|
break;
|
|
case SEC_BATTERY_CHECK_FUELGAUGE:
|
|
psy_name = battery->pdata->fuelgauge_name;
|
|
break;
|
|
case SEC_BATTERY_CHECK_CHARGER_AND_ADC:
|
|
case SEC_BATTERY_CHECK_CHARGER:
|
|
psy_name = battery->pdata->charger_name;
|
|
break;
|
|
default:
|
|
dev_err(battery->dev,
|
|
"%s: Invalid Battery Check Type\n", __func__);
|
|
ret = false;
|
|
goto battery_check_error;
|
|
break;
|
|
}
|
|
|
|
psy_do_property(psy_name, get,
|
|
POWER_SUPPLY_PROP_PRESENT, value);
|
|
ret = (bool)value.intval;
|
|
|
|
battery_check_error:
|
|
return ret;
|
|
}
|
|
|
|
static bool sec_bat_check(struct sec_battery_info *battery)
|
|
{
|
|
bool ret = true;
|
|
|
|
if (battery->factory_mode || battery->is_jig_on || factory_mode) {
|
|
dev_dbg(battery->dev, "%s: No need to check in factory mode\n",
|
|
__func__);
|
|
return ret;
|
|
}
|
|
|
|
if (battery->health != POWER_SUPPLY_HEALTH_GOOD &&
|
|
battery->health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) {
|
|
dev_dbg(battery->dev, "%s: No need to check\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
switch (battery->pdata->battery_check_type) {
|
|
case SEC_BATTERY_CHECK_ADC:
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE)
|
|
ret = battery->present;
|
|
else
|
|
ret = sec_bat_check_vf_adc(battery);
|
|
break;
|
|
case SEC_BATTERY_CHECK_INT:
|
|
case SEC_BATTERY_CHECK_CALLBACK:
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE) {
|
|
ret = battery->present;
|
|
} else {
|
|
if (battery->pdata->check_battery_callback)
|
|
ret = battery->pdata->check_battery_callback();
|
|
}
|
|
break;
|
|
case SEC_BATTERY_CHECK_PMIC:
|
|
case SEC_BATTERY_CHECK_FUELGAUGE:
|
|
case SEC_BATTERY_CHECK_CHARGER:
|
|
ret = sec_bat_check_by_psy(battery);
|
|
break;
|
|
case SEC_BATTERY_CHECK_CHARGER_AND_ADC:
|
|
ret = sec_bat_check_by_psy(battery);
|
|
if (ret) {
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE)
|
|
ret = battery->present;
|
|
else
|
|
ret = sec_bat_check_vf_adc(battery);
|
|
}
|
|
break;
|
|
case SEC_BATTERY_CHECK_NONE:
|
|
dev_dbg(battery->dev, "%s: No Check\n", __func__);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool sec_bat_get_cable_type(
|
|
struct sec_battery_info *battery,
|
|
int cable_source_type)
|
|
{
|
|
bool ret = false;
|
|
int cable_type = battery->cable_type;
|
|
|
|
if (cable_source_type & SEC_BATTERY_CABLE_SOURCE_CALLBACK) {
|
|
if (battery->pdata->check_cable_callback)
|
|
cable_type =
|
|
battery->pdata->check_cable_callback();
|
|
}
|
|
|
|
if (cable_source_type & SEC_BATTERY_CABLE_SOURCE_ADC) {
|
|
if (gpio_get_value_cansleep(
|
|
battery->pdata->bat_gpio_ta_nconnected) ^
|
|
battery->pdata->bat_polarity_ta_nconnected)
|
|
cable_type = SEC_BATTERY_CABLE_NONE;
|
|
else
|
|
cable_type =
|
|
sec_bat_get_charger_type_adc(battery);
|
|
}
|
|
|
|
if (battery->cable_type == cable_type) {
|
|
dev_dbg(battery->dev,
|
|
"%s: No need to change cable status\n", __func__);
|
|
} else {
|
|
if (cable_type < SEC_BATTERY_CABLE_NONE ||
|
|
cable_type >= SEC_BATTERY_CABLE_MAX) {
|
|
dev_err(battery->dev,
|
|
"%s: Invalid cable type\n", __func__);
|
|
} else {
|
|
battery->cable_type = cable_type;
|
|
if (battery->pdata->check_cable_result_callback)
|
|
battery->pdata->check_cable_result_callback(
|
|
battery->cable_type);
|
|
|
|
ret = true;
|
|
|
|
dev_dbg(battery->dev, "%s: Cable Changed (%d)\n",
|
|
__func__, battery->cable_type);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void sec_bat_set_charging_status(struct sec_battery_info *battery,
|
|
int status)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
switch (status) {
|
|
case POWER_SUPPLY_STATUS_CHARGING:
|
|
if (battery->siop_level != 100)
|
|
battery->stop_timer = true;
|
|
break;
|
|
case POWER_SUPPLY_STATUS_NOT_CHARGING:
|
|
case POWER_SUPPLY_STATUS_DISCHARGING:
|
|
if ((battery->status == POWER_SUPPLY_STATUS_FULL ||
|
|
(battery->capacity == 100 && !battery->slate_mode)) &&
|
|
!battery->store_mode) {
|
|
value.intval = 100;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_FULL, value);
|
|
/* To get SOC value (NOT raw SOC), need to reset value */
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
battery->capacity = value.intval;
|
|
}
|
|
battery->expired_time = battery->pdata->expired_time;
|
|
battery->prev_safety_time = 0;
|
|
break;
|
|
case POWER_SUPPLY_STATUS_FULL:
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
#ifdef CONFIG_CS100_JPNCONCEPT
|
|
if (battery->charging_mode == SEC_BATTERY_CHARGING_2ND ||
|
|
battery->charging_passed_time > battery->pdata->charging_total_time) {
|
|
#endif
|
|
value.intval = POWER_SUPPLY_STATUS_FULL;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
#ifdef CONFIG_CS100_JPNCONCEPT
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
battery->status = status;
|
|
}
|
|
|
|
static bool sec_bat_battery_cable_check(struct sec_battery_info *battery)
|
|
{
|
|
if (!sec_bat_check(battery)) {
|
|
if (battery->check_count < battery->pdata->check_count)
|
|
battery->check_count++;
|
|
else {
|
|
dev_err(battery->dev,
|
|
"%s: Battery Disconnected\n", __func__);
|
|
battery->present = false;
|
|
battery->health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
|
|
|
|
if (battery->status !=
|
|
POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
}
|
|
|
|
if (battery->pdata->check_battery_result_callback)
|
|
battery->pdata->
|
|
check_battery_result_callback();
|
|
return false;
|
|
}
|
|
} else
|
|
battery->check_count = 0;
|
|
|
|
battery->present = true;
|
|
|
|
if (battery->health == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) {
|
|
battery->health = POWER_SUPPLY_HEALTH_GOOD;
|
|
|
|
if (battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_CHARGING);
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
if (!battery->swelling_mode)
|
|
#endif
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
}
|
|
}
|
|
|
|
if (battery->pdata->recovery_cable) {
|
|
if (!battery->slate_mode && ((battery->cable_type == SEC_BATTERY_CABLE_NONE &&
|
|
battery->wire_status != SEC_BATTERY_CABLE_NONE) ||
|
|
(battery->cable_type != SEC_BATTERY_CABLE_NONE &&
|
|
battery->wire_status == SEC_BATTERY_CABLE_NONE))) {
|
|
pr_info("%s: Recover from abnormal condition\n",__func__);
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
}
|
|
}
|
|
|
|
dev_dbg(battery->dev, "%s: Battery Connected\n", __func__);
|
|
|
|
if (battery->pdata->cable_check_type &
|
|
SEC_BATTERY_CABLE_CHECK_POLLING) {
|
|
if (sec_bat_get_cable_type(battery,
|
|
battery->pdata->cable_source_type)) {
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static int sec_bat_ovp_uvlo_by_psy(struct sec_battery_info *battery)
|
|
{
|
|
char *psy_name = NULL;
|
|
union power_supply_propval value = {0, };
|
|
|
|
value.intval = POWER_SUPPLY_HEALTH_GOOD;
|
|
|
|
switch (battery->pdata->ovp_uvlo_check_type) {
|
|
case SEC_BATTERY_OVP_UVLO_PMICPOLLING:
|
|
psy_name = battery->pdata->pmic_name;
|
|
break;
|
|
case SEC_BATTERY_OVP_UVLO_CHGPOLLING:
|
|
psy_name = battery->pdata->charger_name;
|
|
break;
|
|
default:
|
|
dev_err(battery->dev,
|
|
"%s: Invalid OVP/UVLO Check Type\n", __func__);
|
|
goto ovp_uvlo_check_error;
|
|
break;
|
|
}
|
|
|
|
psy_do_property(psy_name, get,
|
|
POWER_SUPPLY_PROP_HEALTH, value);
|
|
|
|
ovp_uvlo_check_error:
|
|
return value.intval;
|
|
}
|
|
|
|
static bool sec_bat_ovp_uvlo_result(
|
|
struct sec_battery_info *battery, int health)
|
|
{
|
|
if (battery->health != health) {
|
|
battery->health = health;
|
|
switch (health) {
|
|
case POWER_SUPPLY_HEALTH_GOOD:
|
|
dev_info(battery->dev, "%s: Safe voltage\n", __func__);
|
|
dev_info(battery->dev, "%s: is_recharging : %d\n", __func__, battery->is_recharging);
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_CHARGING);
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_1ST;
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
if (!battery->swelling_mode)
|
|
#endif
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
battery->health_check_count = 0;
|
|
break;
|
|
case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
|
|
case POWER_SUPPLY_HEALTH_UNDERVOLTAGE:
|
|
dev_info(battery->dev,
|
|
"%s: Unsafe voltage (%d)\n",
|
|
__func__, health);
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->is_recharging = false;
|
|
battery->health_check_count = DEFAULT_HEALTH_CHECK_COUNT;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_UNSAFETY_VOLTAGE]++;
|
|
battery->cisd.data[CISD_DATA_UNSAFE_VOLTAGE_PER_DAY]++;
|
|
#endif
|
|
/* Take the wakelock during 10 seconds
|
|
* when over-voltage status is detected
|
|
*/
|
|
wake_lock_timeout(&battery->vbus_wake_lock, HZ * 10);
|
|
break;
|
|
}
|
|
power_supply_changed(battery->psy_bat);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool sec_bat_ovp_uvlo(struct sec_battery_info *battery)
|
|
{
|
|
int health = POWER_SUPPLY_HEALTH_GOOD;
|
|
|
|
if (battery->wdt_kick_disable) {
|
|
dev_dbg(battery->dev,
|
|
"%s: No need to check in wdt test\n",
|
|
__func__);
|
|
return false;
|
|
} else if ((battery->status == POWER_SUPPLY_STATUS_FULL) &&
|
|
(battery->charging_mode == SEC_BATTERY_CHARGING_NONE)) {
|
|
dev_dbg(battery->dev, "%s: No need to check in Full status", __func__);
|
|
return false;
|
|
}
|
|
|
|
if (battery->health != POWER_SUPPLY_HEALTH_GOOD &&
|
|
battery->health != POWER_SUPPLY_HEALTH_OVERVOLTAGE &&
|
|
battery->health != POWER_SUPPLY_HEALTH_UNDERVOLTAGE) {
|
|
dev_dbg(battery->dev, "%s: No need to check\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
health = battery->health;
|
|
|
|
switch (battery->pdata->ovp_uvlo_check_type) {
|
|
case SEC_BATTERY_OVP_UVLO_CALLBACK:
|
|
if (battery->pdata->ovp_uvlo_callback)
|
|
health = battery->pdata->ovp_uvlo_callback();
|
|
break;
|
|
case SEC_BATTERY_OVP_UVLO_PMICPOLLING:
|
|
case SEC_BATTERY_OVP_UVLO_CHGPOLLING:
|
|
health = sec_bat_ovp_uvlo_by_psy(battery);
|
|
break;
|
|
case SEC_BATTERY_OVP_UVLO_PMICINT:
|
|
case SEC_BATTERY_OVP_UVLO_CHGINT:
|
|
/* nothing for interrupt check */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Move the location for calling the get_health
|
|
* in case of attaching the jig
|
|
*/
|
|
if (battery->factory_mode || battery->is_jig_on) {
|
|
dev_dbg(battery->dev,
|
|
"%s: No need to check in factory mode\n",
|
|
__func__);
|
|
return false;
|
|
}
|
|
|
|
return sec_bat_ovp_uvlo_result(battery, health);
|
|
}
|
|
|
|
static bool sec_bat_check_recharge(struct sec_battery_info *battery)
|
|
{
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
if (battery->swelling_mode == SWELLING_MODE_CHARGING ||
|
|
battery->swelling_mode == SWELLING_MODE_FULL) {
|
|
pr_info("%s: Skip normal recharge check routine for swelling mode\n",
|
|
__func__);
|
|
return false;
|
|
}
|
|
#endif
|
|
if ((battery->status == POWER_SUPPLY_STATUS_CHARGING) &&
|
|
(battery->pdata->full_condition_type &
|
|
SEC_BATTERY_FULL_CONDITION_NOTIMEFULL) &&
|
|
(battery->charging_mode == SEC_BATTERY_CHARGING_NONE)) {
|
|
dev_info(battery->dev,
|
|
"%s: Re-charging by NOTIMEFULL (%d)\n",
|
|
__func__, battery->capacity);
|
|
goto check_recharge_check_count;
|
|
}
|
|
|
|
if (battery->status == POWER_SUPPLY_STATUS_FULL &&
|
|
battery->charging_mode == SEC_BATTERY_CHARGING_NONE) {
|
|
int recharging_voltage = battery->pdata->recharge_condition_vcell;
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_MODE) {
|
|
/* float voltage - 150mV (B2B CL : - 200) */
|
|
recharging_voltage =\
|
|
(battery->pdata->chg_float_voltage /\
|
|
battery->pdata->chg_float_voltage_conv) - battery->pdata->swelling_low_rechg_thr;
|
|
dev_info(battery->dev, "%s: recharging voltage changed by low temp(%d)\n",
|
|
__func__, recharging_voltage);
|
|
}
|
|
dev_info(battery->dev, "%s: recharging voltage (%d)\n",
|
|
__func__, recharging_voltage);
|
|
|
|
if ((battery->pdata->recharge_condition_type &
|
|
SEC_BATTERY_RECHARGE_CONDITION_SOC) &&
|
|
(battery->capacity <=
|
|
battery->pdata->recharge_condition_soc)) {
|
|
battery->expired_time = battery->pdata->recharging_expired_time;
|
|
battery->prev_safety_time = 0;
|
|
dev_info(battery->dev,
|
|
"%s: Re-charging by SOC (%d)\n",
|
|
__func__, battery->capacity);
|
|
goto check_recharge_check_count;
|
|
}
|
|
|
|
if ((battery->pdata->recharge_condition_type &
|
|
SEC_BATTERY_RECHARGE_CONDITION_AVGVCELL) &&
|
|
(battery->voltage_avg <= recharging_voltage)) {
|
|
battery->expired_time = battery->pdata->recharging_expired_time;
|
|
battery->prev_safety_time = 0;
|
|
dev_info(battery->dev,
|
|
"%s: Re-charging by average VCELL (%d)\n",
|
|
__func__, battery->voltage_avg);
|
|
goto check_recharge_check_count;
|
|
}
|
|
|
|
if ((battery->pdata->recharge_condition_type &
|
|
SEC_BATTERY_RECHARGE_CONDITION_VCELL) &&
|
|
(battery->voltage_now <= recharging_voltage)) {
|
|
battery->expired_time = battery->pdata->recharging_expired_time;
|
|
battery->prev_safety_time = 0;
|
|
dev_info(battery->dev,
|
|
"%s: Re-charging by VCELL (%d)\n",
|
|
__func__, battery->voltage_now);
|
|
goto check_recharge_check_count;
|
|
}
|
|
}
|
|
|
|
battery->recharge_check_cnt = 0;
|
|
return false;
|
|
|
|
check_recharge_check_count:
|
|
if (battery->recharge_check_cnt <
|
|
battery->pdata->recharge_check_count)
|
|
battery->recharge_check_cnt++;
|
|
dev_dbg(battery->dev,
|
|
"%s: recharge count = %d\n",
|
|
__func__, battery->recharge_check_cnt);
|
|
|
|
if (battery->recharge_check_cnt >=
|
|
battery->pdata->recharge_check_count)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool sec_bat_voltage_check(struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
if (battery->status == POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
dev_dbg(battery->dev,
|
|
"%s: Charging Disabled\n", __func__);
|
|
return true;
|
|
}
|
|
|
|
/* OVP/UVLO check */
|
|
if (sec_bat_ovp_uvlo(battery)) {
|
|
if (battery->pdata->ovp_uvlo_result_callback)
|
|
battery->pdata->
|
|
ovp_uvlo_result_callback(battery->health);
|
|
return false;
|
|
}
|
|
|
|
if ((battery->status == POWER_SUPPLY_STATUS_FULL) &&
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
(battery->charging_mode == SEC_BATTERY_CHARGING_2ND ||
|
|
battery->is_recharging || battery->swelling_mode)) {
|
|
#else
|
|
(battery->charging_mode == SEC_BATTERY_CHARGING_2ND ||
|
|
battery->is_recharging)) {
|
|
#endif
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
if (value.intval <
|
|
battery->pdata->full_condition_soc &&
|
|
battery->voltage_now <
|
|
(battery->pdata->recharge_condition_vcell - 50)) {
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_CHARGING);
|
|
dev_info(battery->dev,
|
|
"%s: battery status full -> charging, RepSOC(%d)\n", __func__, value.intval);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Re-Charging check */
|
|
if (sec_bat_check_recharge(battery)) {
|
|
if (battery->pdata->full_check_type !=
|
|
SEC_BATTERY_FULLCHARGED_NONE)
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_1ST;
|
|
else
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_2ND;
|
|
battery->is_recharging = true;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.recharge_count++;
|
|
battery->cisd.recharge_count_2++;
|
|
battery->cisd.data[CISD_DATA_RECHARGING_COUNT]++;
|
|
battery->cisd.data[CISD_DATA_RECHARGING_COUNT_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
if (!battery->swelling_mode)
|
|
#endif
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void sec_bat_set_swelling_float_voltage(struct sec_battery_info *battery, int float_voltage)
|
|
{
|
|
union power_supply_propval val = {0, };
|
|
|
|
val.intval = float_voltage;
|
|
|
|
if ((battery->voltage_now <= battery->pdata->wa_volt_recov) && (float_voltage == battery->pdata->wa_float_voltage)) {
|
|
/*enable cnt for sudden voltage drop */
|
|
if (battery->wa_float_cnt <
|
|
battery->pdata->wa_fl_check_count) {
|
|
battery->wa_float_cnt++;
|
|
dev_err(battery->dev,
|
|
"%s:wa_float_cnt = %d\n",
|
|
__func__, battery->wa_float_cnt);
|
|
} else {
|
|
val.intval = battery->pdata->swelling_drop_float_voltage;
|
|
}
|
|
} else if (float_voltage > battery->pdata->swelling_drop_float_voltage) {
|
|
if (battery->voltage_now >= battery->pdata->wa_volt_thr) {
|
|
val.intval = battery->pdata->wa_float_voltage;
|
|
battery->wa_float_cnt = 0;
|
|
} else {
|
|
val.intval = battery->pdata->swelling_drop_float_voltage;
|
|
}
|
|
} else {
|
|
battery->wa_float_cnt = 0;
|
|
}
|
|
|
|
if (float_voltage != val.intval) {
|
|
if (!battery->charging_block) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
} else {
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
}
|
|
pr_info("%s: float voltage change(%d -> %d)\n", __func__, float_voltage, val.intval);
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
static void sec_bat_swelling_check(struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval val = {0, };
|
|
int swelling_rechg_voltage = battery->pdata->swelling_high_rechg_voltage;
|
|
bool en_swelling = false, en_rechg = false;
|
|
int float_voltage = battery->pdata->swelling_drop_float_voltage;
|
|
int swelling_high_recovery = battery->pdata->swelling_high_temp_recov;
|
|
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
swelling_high_recovery = battery->pdata->swelling_wc_high_temp_recov;
|
|
}
|
|
pr_info("%s: swelling highblock(%d), highrecov(%d)\n",
|
|
__func__, battery->pdata->swelling_high_temp_block, swelling_high_recovery);
|
|
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
|
|
pr_info("%s: status(%d), swell_mode(%d:%d:%d), cv(%d)mV, temp(%d)\n",
|
|
__func__, battery->status, battery->swelling_mode,
|
|
battery->charging_block, (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_MODE),
|
|
val.intval, battery->temperature);
|
|
|
|
/* swelling_mode
|
|
under voltage over voltage, battery missing */
|
|
if ((battery->status == POWER_SUPPLY_STATUS_DISCHARGING) ||\
|
|
(battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
|
|
battery->skip_swelling || !battery->pdata->temp_check_type) {
|
|
pr_debug("%s: DISCHARGING or NOT-CHARGING or 15 test mode or NOT-check TEMP. Stop swelling mode\n",
|
|
__func__);
|
|
battery->swelling_mode = SWELLING_MODE_NONE;
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
goto skip_swelling_check;
|
|
}
|
|
|
|
if (!battery->swelling_mode) {
|
|
if ((battery->temperature >= battery->pdata->swelling_high_temp_block) &&
|
|
battery->pdata->temp_check_type) {
|
|
pr_info("%s: swelling mode start. stop charging\n", __func__);
|
|
battery->swelling_mode = SWELLING_MODE_CHARGING;
|
|
battery->swelling_full_check_cnt = 0;
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_HIGH_TEMP_SWELLING]++;
|
|
battery->cisd.data[CISD_DATA_HIGH_TEMP_SWELLING_PER_DAY]++;
|
|
#endif
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
en_swelling = true;
|
|
} else if ((battery->temperature <= battery->pdata->swelling_low_temp_block_2nd) &&
|
|
!(battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND)) {
|
|
pr_info("%s: 2nd low temperature swelling step!! reduce current\n", __func__);
|
|
if (battery->pdata->temp_check_type && !battery->pdata->lowtemp_support_full_volt) {
|
|
pr_info("%s: swelling mode start. stop charging\n", __func__);
|
|
battery->swelling_mode = SWELLING_MODE_CHARGING;
|
|
battery->swelling_full_check_cnt = 0;
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_LOW_TEMP_SWELLING]++;
|
|
battery->cisd.data[CISD_DATA_LOW_TEMP_SWELLING_PER_DAY]++;
|
|
#endif
|
|
}
|
|
en_swelling = true;
|
|
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
} else if ((battery->temperature <= battery->pdata->swelling_low_temp_block_1st) &&
|
|
!(battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_MODE)) {
|
|
pr_info("%s: low temperature reduce current\n", __func__);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
} else if ((battery->temperature >= battery->pdata->swelling_low_temp_recov_1st) &&
|
|
(battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING)) {
|
|
pr_info("%s: normal temperature temperature recover current\n", __func__);
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING);
|
|
} else if ((battery->temperature >= battery->pdata->swelling_low_temp_recov_2nd) &&
|
|
(battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND)) {
|
|
if (battery->temperature < battery->pdata->swelling_low_temp_recov_1st) {
|
|
pr_info("%s: upto 2nd low temperature swelling recovery temp! 1st low temp swelling current set\n", __func__);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
|
|
} else {
|
|
pr_info("%s: normal temperature temperature recover current\n", __func__);
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!battery->voltage_now)
|
|
return;
|
|
|
|
if (battery->swelling_mode) {
|
|
if (!battery->pdata->lowtemp_support_full_volt &&
|
|
battery->temperature <= battery->pdata->swelling_low_temp_recov_2nd) {
|
|
swelling_rechg_voltage = battery->pdata->swelling_low_rechg_voltage;
|
|
}
|
|
|
|
if (val.intval != float_voltage) {
|
|
pr_info("%s: float voltage change(%d -> %d)\n", __func__, val.intval, float_voltage);
|
|
if (!battery->charging_block) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
val.intval = float_voltage;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
} else {
|
|
val.intval = float_voltage;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
}
|
|
}
|
|
|
|
if ((battery->pdata->lowtemp_support_full_volt && battery->temperature <= swelling_high_recovery) ||
|
|
(!battery->pdata->lowtemp_support_full_volt && (battery->temperature <= swelling_high_recovery) &&
|
|
(battery->temperature >= battery->pdata->swelling_low_temp_recov_2nd))) {
|
|
pr_info("%s: swelling mode end. restart charging\n", __func__);
|
|
battery->swelling_mode = SWELLING_MODE_NONE;
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_1ST;
|
|
|
|
if (!battery->pdata->lowtemp_support_full_volt) {
|
|
if ((battery->temperature <= battery->pdata->swelling_low_temp_block_1st) ||
|
|
((battery->temperature < battery->pdata->swelling_low_temp_recov_1st) &&
|
|
(battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND))) {
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
} else {
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
}
|
|
} else {
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
}
|
|
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
/* restore 4.4V float voltage */
|
|
val.intval = battery->pdata->swelling_normal_float_voltage;
|
|
if (val.intval != float_voltage) {
|
|
pr_info("%s: float voltage change(%d -> %d)\n", __func__, val.intval, float_voltage);
|
|
if (!battery->charging_block) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
} else {
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
}
|
|
}
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_SWELLING_RECOVERY_CNT]++;
|
|
battery->cisd.data[CISD_DATA_SWELLING_RECOVERY_CNT_PER_DAY]++;
|
|
#endif
|
|
} else if (battery->voltage_now < swelling_rechg_voltage &&
|
|
battery->charging_block) {
|
|
pr_info("%s: swelling mode recharging start. Vbatt(%d)\n",
|
|
__func__, battery->voltage_now);
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_1ST;
|
|
en_rechg = true;
|
|
|
|
/* set charging enable */
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
if (battery->temperature > swelling_high_recovery) {
|
|
pr_info("%s: swelling mode reduce charging current(HIGH-temp:%d)\n",
|
|
__func__, battery->temperature);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
}
|
|
|
|
if (!battery->pdata->lowtemp_support_full_volt) {
|
|
if (battery->temperature < battery->pdata->swelling_low_temp_recov_2nd) {
|
|
pr_info("%s: swelling mode reduce charging current(LOW-temp:%d)\n",
|
|
__func__, battery->temperature);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_SWELLING_CHARGING_COUNT]++;
|
|
battery->cisd.data[CISD_DATA_SWELLING_CHARGING_COUNT_PER_DAY]++;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (en_swelling && !en_rechg) {
|
|
pr_info("%s : SAFETY TIME RESET (SWELLING MODE CHARGING STOP!)\n", __func__);
|
|
battery->expired_time = battery->pdata->expired_time;
|
|
battery->prev_safety_time = 0;
|
|
}
|
|
|
|
skip_swelling_check:
|
|
dev_dbg(battery->dev, "%s end\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
static bool sec_bat_set_aging_step(struct sec_battery_info *battery, int step)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
if (battery->pdata->num_age_step <= 0 || step < 0 || step >= battery->pdata->num_age_step) {
|
|
pr_info("%s: [AGE] abnormal age step : %d/%d\n",
|
|
__func__, step, battery->pdata->num_age_step-1);
|
|
return false;
|
|
}
|
|
|
|
battery->pdata->age_step = step;
|
|
|
|
/* float voltage */
|
|
battery->pdata->chg_float_voltage =
|
|
battery->pdata->age_data[battery->pdata->age_step].float_voltage;
|
|
battery->pdata->swelling_normal_float_voltage =
|
|
battery->pdata->chg_float_voltage;
|
|
if (!battery->swelling_mode) {
|
|
value.intval = battery->pdata->chg_float_voltage;
|
|
if (!battery->charging_block) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, value);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
} else {
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, value);
|
|
}
|
|
}
|
|
|
|
/* full/recharge condition */
|
|
battery->pdata->recharge_condition_vcell =
|
|
battery->pdata->age_data[battery->pdata->age_step].recharge_condition_vcell;
|
|
battery->pdata->full_condition_soc =
|
|
battery->pdata->age_data[battery->pdata->age_step].full_condition_soc;
|
|
battery->pdata->full_condition_vcell =
|
|
battery->pdata->age_data[battery->pdata->age_step].full_condition_vcell;
|
|
|
|
#if defined(CONFIG_FUELGAUGE_S2MU004) || defined(CONFIG_FUELGAUGE_S2MU005) || defined(CONFIG_FUELGAUGE_S2MU106) || defined(CONFIG_FUELGAUGE_S2MU205)
|
|
value.intval = battery->pdata->age_step;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_EXT_PROP_UPDATE_BATTERY_DATA, value);
|
|
#else
|
|
value.intval = battery->pdata->full_condition_soc;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_CAPACITY_LEVEL, value);
|
|
#endif
|
|
#if defined(CONFIG_STEP_CHARGING)
|
|
sec_bat_set_aging_info_step_charging(battery);
|
|
#endif
|
|
|
|
dev_info(battery->dev,
|
|
"%s: Step(%d/%d), Cycle(%d), float_v(%d), r_v(%d), f_s(%d), f_vl(%d)\n",
|
|
__func__,
|
|
battery->pdata->age_step, battery->pdata->num_age_step-1, battery->batt_cycle,
|
|
battery->pdata->chg_float_voltage,
|
|
battery->pdata->recharge_condition_vcell,
|
|
battery->pdata->full_condition_soc,
|
|
battery->pdata->full_condition_vcell);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void sec_bat_aging_check(struct sec_battery_info *battery)
|
|
{
|
|
int prev_step = battery->pdata->age_step;
|
|
int calc_step = -1;
|
|
bool ret = 0;
|
|
|
|
if (battery->pdata->num_age_step <= 0 || battery->batt_cycle < 0)
|
|
return;
|
|
|
|
if (battery->temperature < 50) {
|
|
pr_info("%s: [AGE] skip (temperature:%d)\n", __func__, battery->temperature);
|
|
return;
|
|
}
|
|
|
|
for (calc_step = battery->pdata->num_age_step - 1; calc_step >= 0; calc_step--) {
|
|
if (battery->pdata->age_data[calc_step].cycle <= battery->batt_cycle)
|
|
break;
|
|
}
|
|
|
|
dev_info(battery->dev,
|
|
"%s: [Long life] prev_step = %d, calc_step = %d\n", __func__, prev_step, calc_step);
|
|
|
|
if (calc_step == prev_step)
|
|
return;
|
|
|
|
ret = sec_bat_set_aging_step(battery, calc_step);
|
|
dev_info(battery->dev,
|
|
"%s: %s change step (%d->%d), Cycle(%d)\n",
|
|
__func__, ret ? "Succeed in" : "Fail to",
|
|
prev_step, battery->pdata->age_step, battery->batt_cycle);
|
|
}
|
|
#endif
|
|
|
|
static bool sec_bat_temperature(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
bool ret;
|
|
ret = true;
|
|
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
battery->temp_highlimit_threshold =
|
|
battery->pdata->temp_highlimit_threshold_normal;
|
|
battery->temp_highlimit_recovery =
|
|
battery->pdata->temp_highlimit_recovery_normal;
|
|
battery->temp_high_threshold =
|
|
battery->pdata->wpc_high_threshold_normal;
|
|
battery->temp_high_recovery =
|
|
battery->pdata->wpc_high_recovery_normal;
|
|
battery->temp_low_recovery =
|
|
battery->pdata->wpc_low_recovery_normal;
|
|
battery->temp_low_threshold =
|
|
battery->pdata->wpc_low_threshold_normal;
|
|
} else {
|
|
if (lpcharge) {
|
|
battery->temp_highlimit_threshold =
|
|
battery->pdata->temp_highlimit_threshold_lpm;
|
|
battery->temp_highlimit_recovery =
|
|
battery->pdata->temp_highlimit_recovery_lpm;
|
|
battery->temp_high_threshold =
|
|
battery->pdata->temp_high_threshold_lpm;
|
|
battery->temp_high_recovery =
|
|
battery->pdata->temp_high_recovery_lpm;
|
|
battery->temp_low_recovery =
|
|
battery->pdata->temp_low_recovery_lpm;
|
|
battery->temp_low_threshold =
|
|
battery->pdata->temp_low_threshold_lpm;
|
|
} else {
|
|
battery->temp_highlimit_threshold =
|
|
battery->pdata->temp_highlimit_threshold_normal;
|
|
battery->temp_highlimit_recovery =
|
|
battery->pdata->temp_highlimit_recovery_normal;
|
|
battery->temp_high_threshold =
|
|
battery->pdata->temp_high_threshold_normal;
|
|
battery->temp_high_recovery =
|
|
battery->pdata->temp_high_recovery_normal;
|
|
battery->temp_low_recovery =
|
|
battery->pdata->temp_low_recovery_normal;
|
|
battery->temp_low_threshold =
|
|
battery->pdata->temp_low_threshold_normal;
|
|
}
|
|
}
|
|
dev_info(battery->dev,
|
|
"%s: HLT(%d) HLR(%d) HT(%d), HR(%d), LT(%d), LR(%d)\n",
|
|
__func__, battery->temp_highlimit_threshold,
|
|
battery->temp_highlimit_recovery,
|
|
battery->temp_high_threshold,
|
|
battery->temp_high_recovery,
|
|
battery->temp_low_threshold,
|
|
battery->temp_low_recovery);
|
|
return ret;
|
|
}
|
|
|
|
static bool sec_bat_temperature_check(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
int temp_value = 0;
|
|
int pre_health = POWER_SUPPLY_HEALTH_GOOD;
|
|
|
|
if (battery->status == POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
battery->health_change = false;
|
|
dev_dbg(battery->dev,
|
|
"%s: Charging Disabled\n", __func__);
|
|
return true;
|
|
}
|
|
|
|
if (battery->health != POWER_SUPPLY_HEALTH_GOOD &&
|
|
battery->health != POWER_SUPPLY_HEALTH_OVERHEAT &&
|
|
battery->health != POWER_SUPPLY_HEALTH_COLD &&
|
|
battery->health != POWER_SUPPLY_HEALTH_OVERHEATLIMIT) {
|
|
dev_dbg(battery->dev, "%s: No need to check\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT) || defined(CONFIG_SEC_FACTORY)
|
|
if (!battery->cooldown_mode) {
|
|
dev_err(battery->dev, "%s: Forced temp check block\n", __func__);
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
sec_bat_temperature(battery);
|
|
|
|
switch (battery->pdata->temp_check_type) {
|
|
case SEC_BATTERY_TEMP_CHECK_ADC:
|
|
temp_value = battery->temp_adc;
|
|
break;
|
|
case SEC_BATTERY_TEMP_CHECK_TEMP:
|
|
temp_value = battery->temperature;
|
|
break;
|
|
default:
|
|
dev_err(battery->dev,
|
|
"%s: Invalid Temp Check Type\n", __func__);
|
|
return true;
|
|
}
|
|
pre_health = battery->health;
|
|
|
|
if (battery->pdata->usb_thermal_source &&
|
|
(battery->usb_temp >= battery->temp_highlimit_threshold)) {
|
|
if (battery->health != POWER_SUPPLY_HEALTH_OVERHEATLIMIT) {
|
|
if (battery->temp_highlimit_cnt <
|
|
battery->pdata->temp_check_count) {
|
|
battery->temp_highlimit_cnt++;
|
|
battery->temp_high_cnt = 0;
|
|
battery->temp_low_cnt = 0;
|
|
battery->temp_recover_cnt = 0;
|
|
}
|
|
dev_err(battery->dev,
|
|
"%s: usb therm highlimit count = %d\n",
|
|
__func__, battery->temp_highlimit_cnt);
|
|
}
|
|
} else if (battery->pdata->usb_thermal_source &&
|
|
(battery->usb_temp > battery->temp_highlimit_recovery) &&
|
|
(battery->health == POWER_SUPPLY_HEALTH_OVERHEATLIMIT)) {
|
|
dev_err(battery->dev,
|
|
"%s: usb therm highlimit\n", __func__);
|
|
} else if (temp_value >= battery->temp_highlimit_threshold && !battery->pdata->usb_thermal_source) {
|
|
if (battery->health != POWER_SUPPLY_HEALTH_OVERHEATLIMIT) {
|
|
if (battery->temp_highlimit_cnt <
|
|
battery->pdata->temp_check_count) {
|
|
battery->temp_highlimit_cnt++;
|
|
battery->temp_high_cnt = 0;
|
|
battery->temp_low_cnt = 0;
|
|
battery->temp_recover_cnt = 0;
|
|
}
|
|
dev_err(battery->dev,
|
|
"%s: highlimit count = %d\n",
|
|
__func__, battery->temp_highlimit_cnt);
|
|
}
|
|
} else if (temp_value >= battery->temp_high_threshold) {
|
|
if (battery->health == POWER_SUPPLY_HEALTH_OVERHEATLIMIT &&
|
|
!battery->pdata->usb_thermal_source) {
|
|
if (temp_value <= battery->temp_highlimit_recovery) {
|
|
if (battery->temp_recover_cnt <
|
|
battery->pdata->temp_check_count) {
|
|
battery->temp_recover_cnt++;
|
|
battery->temp_highlimit_cnt = 0;
|
|
battery->temp_high_cnt = 0;
|
|
battery->temp_low_cnt = 0;
|
|
}
|
|
dev_err(battery->dev,
|
|
"%s: recovery count = %d\n",
|
|
__func__, battery->temp_recover_cnt);
|
|
}
|
|
} else if (battery->health != POWER_SUPPLY_HEALTH_OVERHEAT) {
|
|
if (battery->temp_high_cnt <
|
|
battery->pdata->temp_check_count) {
|
|
battery->temp_high_cnt++;
|
|
battery->temp_highlimit_cnt = 0;
|
|
battery->temp_low_cnt = 0;
|
|
battery->temp_recover_cnt = 0;
|
|
}
|
|
dev_err(battery->dev,
|
|
"%s: high count = %d\n",
|
|
__func__, battery->temp_high_cnt);
|
|
}
|
|
} else if ((temp_value <= battery->temp_high_recovery) &&
|
|
(temp_value >= battery->temp_low_recovery)) {
|
|
if (battery->health == POWER_SUPPLY_HEALTH_OVERHEAT ||
|
|
battery->health == POWER_SUPPLY_HEALTH_OVERHEATLIMIT ||
|
|
battery->health == POWER_SUPPLY_HEALTH_COLD) {
|
|
if (battery->temp_recover_cnt <
|
|
battery->pdata->temp_check_count) {
|
|
battery->temp_recover_cnt++;
|
|
battery->temp_highlimit_cnt = 0;
|
|
battery->temp_high_cnt = 0;
|
|
battery->temp_low_cnt = 0;
|
|
}
|
|
dev_err(battery->dev,
|
|
"%s: recovery count = %d\n",
|
|
__func__, battery->temp_recover_cnt);
|
|
}
|
|
} else if (temp_value <= battery->temp_low_threshold) {
|
|
if (battery->health != POWER_SUPPLY_HEALTH_COLD) {
|
|
if (battery->temp_low_cnt <
|
|
battery->pdata->temp_check_count) {
|
|
battery->temp_low_cnt++;
|
|
battery->temp_highlimit_cnt = 0;
|
|
battery->temp_high_cnt = 0;
|
|
battery->temp_recover_cnt = 0;
|
|
}
|
|
dev_err(battery->dev,
|
|
"%s: low count = %d\n",
|
|
__func__, battery->temp_low_cnt);
|
|
}
|
|
} else {
|
|
battery->temp_highlimit_cnt = 0;
|
|
battery->temp_high_cnt = 0;
|
|
battery->temp_low_cnt = 0;
|
|
battery->temp_recover_cnt = 0;
|
|
}
|
|
|
|
if (battery->temp_highlimit_cnt >=
|
|
battery->pdata->temp_check_count) {
|
|
battery->health = POWER_SUPPLY_HEALTH_OVERHEATLIMIT;
|
|
battery->temp_highlimit_cnt = 0;
|
|
} else if (battery->temp_high_cnt >=
|
|
battery->pdata->temp_check_count) {
|
|
battery->health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
|
battery->temp_high_cnt = 0;
|
|
} else if (battery->temp_low_cnt >=
|
|
battery->pdata->temp_check_count) {
|
|
battery->health = POWER_SUPPLY_HEALTH_COLD;
|
|
battery->temp_low_cnt = 0;
|
|
} else if (battery->temp_recover_cnt >=
|
|
battery->pdata->temp_check_count) {
|
|
if (battery->health == POWER_SUPPLY_HEALTH_OVERHEATLIMIT &&
|
|
temp_value > battery->temp_high_recovery) {
|
|
battery->health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
|
} else {
|
|
battery->health = POWER_SUPPLY_HEALTH_GOOD;
|
|
}
|
|
battery->temp_recover_cnt = 0;
|
|
}
|
|
if (pre_health != battery->health) {
|
|
battery->health_change = true;
|
|
dev_info(battery->dev, "%s, health_change true\n", __func__);
|
|
} else {
|
|
battery->health_change = false;
|
|
}
|
|
|
|
if ((battery->health == POWER_SUPPLY_HEALTH_OVERHEAT) ||
|
|
(battery->health == POWER_SUPPLY_HEALTH_COLD) ||
|
|
(battery->health == POWER_SUPPLY_HEALTH_OVERHEATLIMIT)) {
|
|
union power_supply_propval val = {0, };
|
|
if (battery->health_change) {
|
|
battery->is_abnormal_temp = true;
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
val.intval = battery->health;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_HEALTH, val);
|
|
}
|
|
dev_info(battery->dev,
|
|
"%s: Unsafe Temperature\n", __func__);
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_UNSAFETY_TEMPERATURE]++;
|
|
battery->cisd.data[CISD_DATA_UNSAFE_TEMPERATURE_PER_DAY]++;
|
|
#endif
|
|
|
|
if (battery->health == POWER_SUPPLY_HEALTH_OVERHEATLIMIT) {
|
|
/* change charging current to battery (default 0mA) */
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
} else {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
}
|
|
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
sec_bat_set_swelling_float_voltage(battery, val.intval);
|
|
|
|
return false;
|
|
}
|
|
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
sec_bat_set_swelling_float_voltage(battery, val.intval);
|
|
} else {
|
|
/* if recovered from not charging */
|
|
if ((battery->health == POWER_SUPPLY_HEALTH_GOOD) &&
|
|
(battery->status ==
|
|
POWER_SUPPLY_STATUS_NOT_CHARGING)) {
|
|
battery->is_abnormal_temp = false;
|
|
dev_info(battery->dev,
|
|
"%s: Safe Temperature\n", __func__);
|
|
if (battery->capacity >= 100)
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_FULL);
|
|
else /* Normal Charging */
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_CHARGING);
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
if (battery->temperature > battery->pdata->swelling_high_temp_recov ||
|
|
(!battery->pdata->lowtemp_support_full_volt && battery->temperature <= battery->pdata->swelling_low_temp_recov_2nd)) {
|
|
pr_info("%s: swelling mode start. stop charging\n", __func__);
|
|
battery->swelling_mode = SWELLING_MODE_CHARGING;
|
|
battery->swelling_full_check_cnt = 0;
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
|
|
if (!battery->pdata->lowtemp_support_full_volt && battery->temperature <= battery->pdata->swelling_low_temp_recov_2nd)
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
else
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING);
|
|
} else {
|
|
union power_supply_propval val = {0, };
|
|
/* restore 4.4V float voltage */
|
|
val.intval = battery->pdata->swelling_normal_float_voltage;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
/* turn on charger by cable type */
|
|
if ((battery->status == POWER_SUPPLY_STATUS_FULL) &&
|
|
(battery->charging_mode == SEC_BATTERY_CHARGING_NONE)) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
} else {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
}
|
|
|
|
if (pre_health == POWER_SUPPLY_HEALTH_COLD) {
|
|
if (battery->temperature <= battery->pdata->swelling_low_temp_block_2nd) {
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_2ND,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
} else if (battery->temperature <= battery->pdata->swelling_low_temp_block_1st) {
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
/* turn on charger by cable type */
|
|
if ((battery->status == POWER_SUPPLY_STATUS_FULL) &&
|
|
(battery->charging_mode == SEC_BATTERY_CHARGING_NONE)) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
} else {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool sec_bat_check_fullcharged_condition(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
int full_check_type = SEC_BATTERY_FULLCHARGED_NONE;
|
|
|
|
if (battery->charging_mode == SEC_BATTERY_CHARGING_1ST)
|
|
full_check_type = battery->pdata->full_check_type;
|
|
else
|
|
full_check_type = battery->pdata->full_check_type_2nd;
|
|
|
|
switch (full_check_type) {
|
|
case SEC_BATTERY_FULLCHARGED_ADC:
|
|
case SEC_BATTERY_FULLCHARGED_FG_CURRENT:
|
|
case SEC_BATTERY_FULLCHARGED_SOC:
|
|
case SEC_BATTERY_FULLCHARGED_CHGGPIO:
|
|
case SEC_BATTERY_FULLCHARGED_CHGPSY:
|
|
break;
|
|
|
|
/* If these is NOT full check type or NONE full check type,
|
|
* it is full-charged
|
|
*/
|
|
case SEC_BATTERY_FULLCHARGED_CHGINT:
|
|
case SEC_BATTERY_FULLCHARGED_TIME:
|
|
case SEC_BATTERY_FULLCHARGED_NONE:
|
|
default:
|
|
return true;
|
|
break;
|
|
}
|
|
|
|
if (battery->pdata->full_condition_type &
|
|
SEC_BATTERY_FULL_CONDITION_SOC) {
|
|
if (battery->capacity <
|
|
battery->pdata->full_condition_soc) {
|
|
dev_dbg(battery->dev,
|
|
"%s: Not enough SOC (%d%%)\n",
|
|
__func__, battery->capacity);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (battery->pdata->full_condition_type &
|
|
SEC_BATTERY_FULL_CONDITION_VCELL) {
|
|
if (battery->voltage_now <
|
|
battery->pdata->full_condition_vcell) {
|
|
dev_dbg(battery->dev,
|
|
"%s: Not enough VCELL (%dmV)\n",
|
|
__func__, battery->voltage_now);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (battery->pdata->full_condition_type &
|
|
SEC_BATTERY_FULL_CONDITION_AVGVCELL) {
|
|
if (battery->voltage_avg <
|
|
battery->pdata->full_condition_avgvcell) {
|
|
dev_dbg(battery->dev,
|
|
"%s: Not enough AVGVCELL (%dmV)\n",
|
|
__func__, battery->voltage_avg);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (battery->pdata->full_condition_type &
|
|
SEC_BATTERY_FULL_CONDITION_OCV) {
|
|
if (battery->voltage_ocv <
|
|
battery->pdata->full_condition_ocv) {
|
|
dev_dbg(battery->dev,
|
|
"%s: Not enough OCV (%dmV)\n",
|
|
__func__, battery->voltage_ocv);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void sec_bat_do_test_function(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
switch (battery->test_mode) {
|
|
case 1:
|
|
if (battery->status == POWER_SUPPLY_STATUS_CHARGING) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (battery->status == POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
sec_bat_set_charging_status(battery, value.intval);
|
|
}
|
|
battery->test_mode = 0;
|
|
break;
|
|
case 3: // clear temp block
|
|
battery->health = POWER_SUPPLY_HEALTH_GOOD;
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
break;
|
|
case 4:
|
|
if (battery->status == POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
sec_bat_set_charging_status(battery, value.intval);
|
|
}
|
|
break;
|
|
default:
|
|
pr_info("%s: error test: unknown state\n", __func__);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool sec_bat_time_management(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
struct timespec ts = {0, };
|
|
unsigned long charging_time;
|
|
|
|
if (battery->charging_start_time == 0 || !battery->safety_timer_set) {
|
|
dev_dbg(battery->dev,
|
|
"%s: Charging Disabled\n", __func__);
|
|
return true;
|
|
}
|
|
|
|
get_monotonic_boottime(&ts);
|
|
|
|
if (ts.tv_sec >= battery->charging_start_time) {
|
|
charging_time = ts.tv_sec - battery->charging_start_time;
|
|
} else {
|
|
charging_time = 0xFFFFFFFF - battery->charging_start_time
|
|
+ ts.tv_sec;
|
|
}
|
|
|
|
battery->charging_passed_time = charging_time;
|
|
|
|
switch (battery->status) {
|
|
case POWER_SUPPLY_STATUS_FULL:
|
|
if (battery->expired_time == 0) {
|
|
dev_info(battery->dev,
|
|
"%s: Recharging Timer Expired\n", __func__);
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
battery->is_recharging = false;
|
|
if (sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF)) {
|
|
dev_err(battery->dev,
|
|
"%s: Fail to Set Charger\n", __func__);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_STATUS_CHARGING:
|
|
if ((battery->pdata->full_condition_type &
|
|
SEC_BATTERY_FULL_CONDITION_NOTIMEFULL) &&
|
|
(battery->is_recharging && (battery->expired_time == 0))) {
|
|
dev_info(battery->dev,
|
|
"%s: Recharging Timer Expired\n", __func__);
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
battery->is_recharging = false;
|
|
if (sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF)) {
|
|
dev_err(battery->dev,
|
|
"%s: Fail to Set Charger\n", __func__);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else if (!battery->is_recharging &&
|
|
(battery->expired_time == 0)) {
|
|
dev_info(battery->dev,
|
|
"%s: Charging Timer Expired\n", __func__);
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_SAFETY_TIMER]++;
|
|
battery->cisd.data[CISD_DATA_SAFETY_TIMER_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_SEC_ABC)
|
|
sec_abc_send_event("MODULE=battery@ERROR=safety_timer");
|
|
#endif
|
|
if (sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF)) {
|
|
dev_err(battery->dev,
|
|
"%s: Fail to Set Charger\n", __func__);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
dev_err(battery->dev,
|
|
"%s: Undefine Battery Status\n", __func__);
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool sec_bat_check_fullcharged(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
int current_adc = 0;
|
|
int full_check_type = SEC_BATTERY_FULLCHARGED_NONE;
|
|
bool ret = false;
|
|
int err = 0;
|
|
|
|
if (!sec_bat_check_fullcharged_condition(battery))
|
|
goto not_full_charged;
|
|
|
|
if (battery->charging_mode == SEC_BATTERY_CHARGING_1ST)
|
|
full_check_type = battery->pdata->full_check_type;
|
|
else
|
|
full_check_type = battery->pdata->full_check_type_2nd;
|
|
|
|
switch (full_check_type) {
|
|
case SEC_BATTERY_FULLCHARGED_ADC:
|
|
current_adc =
|
|
sec_bat_get_adc_data(battery,
|
|
SEC_BAT_ADC_CHANNEL_FULL_CHECK,
|
|
battery->pdata->adc_check_count);
|
|
|
|
dev_dbg(battery->dev,
|
|
"%s: Current ADC (%d)\n",
|
|
__func__, current_adc);
|
|
|
|
if (current_adc < 0)
|
|
break;
|
|
battery->current_adc = current_adc;
|
|
|
|
if (battery->current_adc <
|
|
(battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_1ST ?
|
|
battery->pdata->full_check_current_1st :
|
|
battery->pdata->full_check_current_2nd)) {
|
|
battery->full_check_cnt++;
|
|
dev_dbg(battery->dev,
|
|
"%s: Full Check ADC (%d)\n",
|
|
__func__,
|
|
battery->full_check_cnt);
|
|
} else
|
|
battery->full_check_cnt = 0;
|
|
break;
|
|
|
|
case SEC_BATTERY_FULLCHARGED_FG_CURRENT:
|
|
if ((battery->current_now > 0 && battery->current_now <
|
|
(battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_1ST ?
|
|
battery->pdata->full_check_current_1st :
|
|
battery->pdata->full_check_current_2nd)) &&
|
|
(battery->current_avg > 0 && battery->current_avg <
|
|
(battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_1ST ?
|
|
battery->pdata->full_check_current_1st :
|
|
battery->pdata->full_check_current_2nd))) {
|
|
battery->full_check_cnt++;
|
|
dev_dbg(battery->dev,
|
|
"%s: Full Check Current (%d)\n",
|
|
__func__,
|
|
battery->full_check_cnt);
|
|
} else
|
|
battery->full_check_cnt = 0;
|
|
break;
|
|
|
|
case SEC_BATTERY_FULLCHARGED_TIME:
|
|
if ((battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_2ND ?
|
|
(battery->charging_passed_time -
|
|
battery->charging_fullcharged_time) :
|
|
battery->charging_passed_time) >
|
|
(battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_1ST ?
|
|
battery->pdata->full_check_current_1st :
|
|
battery->pdata->full_check_current_2nd)) {
|
|
battery->full_check_cnt++;
|
|
dev_dbg(battery->dev,
|
|
"%s: Full Check Time (%d)\n",
|
|
__func__,
|
|
battery->full_check_cnt);
|
|
} else
|
|
battery->full_check_cnt = 0;
|
|
break;
|
|
|
|
case SEC_BATTERY_FULLCHARGED_SOC:
|
|
if (battery->capacity <=
|
|
(battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_1ST ?
|
|
battery->pdata->full_check_current_1st :
|
|
battery->pdata->full_check_current_2nd)) {
|
|
battery->full_check_cnt++;
|
|
dev_dbg(battery->dev,
|
|
"%s: Full Check SOC (%d)\n",
|
|
__func__,
|
|
battery->full_check_cnt);
|
|
} else
|
|
battery->full_check_cnt = 0;
|
|
break;
|
|
|
|
case SEC_BATTERY_FULLCHARGED_CHGGPIO:
|
|
err = gpio_request(
|
|
battery->pdata->chg_gpio_full_check,
|
|
"GPIO_CHG_FULL");
|
|
if (err) {
|
|
dev_err(battery->dev,
|
|
"%s: Error in Request of GPIO\n", __func__);
|
|
break;
|
|
}
|
|
if (!(gpio_get_value_cansleep(
|
|
battery->pdata->chg_gpio_full_check) ^
|
|
!battery->pdata->chg_polarity_full_check)) {
|
|
battery->full_check_cnt++;
|
|
dev_dbg(battery->dev,
|
|
"%s: Full Check GPIO (%d)\n",
|
|
__func__, battery->full_check_cnt);
|
|
} else
|
|
battery->full_check_cnt = 0;
|
|
gpio_free(battery->pdata->chg_gpio_full_check);
|
|
break;
|
|
|
|
case SEC_BATTERY_FULLCHARGED_CHGINT:
|
|
case SEC_BATTERY_FULLCHARGED_CHGPSY:
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
|
|
if (value.intval == POWER_SUPPLY_STATUS_FULL) {
|
|
battery->full_check_cnt++;
|
|
dev_info(battery->dev,
|
|
"%s: Full Check Charger (%d)\n",
|
|
__func__, battery->full_check_cnt);
|
|
} else
|
|
battery->full_check_cnt = 0;
|
|
break;
|
|
|
|
/* If these is NOT full check type or NONE full check type,
|
|
* it is full-charged
|
|
*/
|
|
case SEC_BATTERY_FULLCHARGED_NONE:
|
|
battery->full_check_cnt = 0;
|
|
ret = true;
|
|
break;
|
|
default:
|
|
dev_err(battery->dev,
|
|
"%s: Invalid Full Check\n", __func__);
|
|
break;
|
|
}
|
|
|
|
if (battery->full_check_cnt >=
|
|
battery->pdata->full_check_count) {
|
|
battery->full_check_cnt = 0;
|
|
ret = true;
|
|
}
|
|
|
|
not_full_charged:
|
|
return ret;
|
|
}
|
|
|
|
static void sec_bat_do_fullcharged(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
/* To let charger/fuel gauge know the full status,
|
|
* set status before calling sec_bat_set_charge()
|
|
*/
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
struct timespec now_ts;
|
|
|
|
if (battery->status != POWER_SUPPLY_STATUS_FULL) {
|
|
battery->cisd.data[CISD_DATA_FULL_COUNT]++;
|
|
battery->cisd.data[CISD_DATA_FULL_COUNT_PER_DAY]++;
|
|
}
|
|
#endif
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_FULL);
|
|
|
|
if (battery->charging_mode == SEC_BATTERY_CHARGING_1ST &&
|
|
battery->pdata->full_check_type_2nd != SEC_BATTERY_FULLCHARGED_NONE) {
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_2ND;
|
|
battery->charging_fullcharged_time = battery->charging_passed_time;
|
|
value.intval = SEC_BAT_CHG_MODE_CHARGING_OFF;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGING_ENABLED, value);
|
|
sec_bat_set_charging_current(battery);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
} else {
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
now_ts = ktime_to_timespec(ktime_get_boottime());
|
|
if (!battery->is_recharging) {
|
|
battery->cisd.charging_end_time = now_ts.tv_sec;
|
|
}
|
|
if (battery->siop_level == 100) {
|
|
dev_info(battery->dev, "%s: cisd - leakage EFGH start(%ld)\n", __func__, ((unsigned long)now_ts.tv_sec));
|
|
battery->cisd.state &= ~(CISD_STATE_LEAK_E|CISD_STATE_LEAK_F|CISD_STATE_LEAK_G);
|
|
battery->cisd.charging_end_time_2 = now_ts.tv_sec;
|
|
battery->cisd.recharge_count_2 = 0;
|
|
} else {
|
|
battery->cisd.state &= ~(CISD_STATE_LEAK_E|CISD_STATE_LEAK_F|CISD_STATE_LEAK_G);
|
|
battery->cisd.recharge_count_2 = 0;
|
|
battery->cisd.charging_end_time_2 = 0;
|
|
}
|
|
#endif
|
|
battery->is_recharging = false;
|
|
|
|
if (!battery->wdt_kick_disable) {
|
|
pr_info("%s: wdt kick enable -> Charger Off, %d\n",
|
|
__func__, battery->wdt_kick_disable);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
} else {
|
|
pr_info("%s: wdt kick disabled -> skip charger off, %d\n",
|
|
__func__, battery->wdt_kick_disable);
|
|
}
|
|
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
sec_bat_aging_check(battery);
|
|
#endif
|
|
|
|
value.intval = POWER_SUPPLY_STATUS_FULL;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
}
|
|
|
|
/* platform can NOT get information of battery
|
|
* because wakeup time is too short to check uevent
|
|
* To make sure that target is wakeup if full-charged,
|
|
* activated wake lock in a few seconds
|
|
*/
|
|
if (battery->pdata->polling_type == SEC_BATTERY_MONITOR_ALARM)
|
|
wake_lock_timeout(&battery->vbus_wake_lock, HZ * 10);
|
|
}
|
|
|
|
static bool sec_bat_fullcharged_check(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
if ((battery->charging_mode == SEC_BATTERY_CHARGING_NONE) ||
|
|
(battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING)) {
|
|
dev_dbg(battery->dev,
|
|
"%s: No Need to Check Full-Charged\n", __func__);
|
|
return true;
|
|
}
|
|
|
|
if (sec_bat_check_fullcharged(battery)) {
|
|
union power_supply_propval value = {0, };
|
|
if (battery->capacity < 100) {
|
|
battery->full_check_cnt = battery->pdata->full_check_count;
|
|
} else {
|
|
sec_bat_do_fullcharged(battery);
|
|
}
|
|
|
|
/* update capacity max */
|
|
value.intval = battery->capacity;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_FULL, value);
|
|
pr_info("%s : forced full-charged sequence for the capacity(%d)\n",
|
|
__func__, battery->capacity);
|
|
}
|
|
|
|
dev_info(battery->dev,
|
|
"%s: Charging Mode : %s\n", __func__,
|
|
battery->is_recharging ?
|
|
sec_bat_charging_mode_str[SEC_BATTERY_CHARGING_RECHARGING] :
|
|
sec_bat_charging_mode_str[battery->charging_mode]);
|
|
|
|
return true;
|
|
}
|
|
|
|
#if defined(CONFIG_ABNORMAL_BAT_THM_WA)
|
|
static void sec_bat_control_temperature(struct sec_battery_info *battery)
|
|
{
|
|
int temp_now = 0, prev_temp = 0;
|
|
int tempOffset = 10;
|
|
|
|
if(battery->status == POWER_SUPPLY_STATUS_CHARGING)
|
|
tempOffset = 5;
|
|
|
|
temp_now = battery->temperature / 10;
|
|
prev_temp = battery->prev_bat_temp / 10;
|
|
|
|
if (!battery->temp_control && (temp_now > prev_temp + tempOffset)) {
|
|
prev_temp += 1;
|
|
battery->temperature = prev_temp * 10;
|
|
battery->temp_control = true;
|
|
} else if (battery->temp_control && (temp_now > prev_temp)) {
|
|
prev_temp += 1;
|
|
battery->temperature = prev_temp * 10;
|
|
} else if (battery->temp_control && (prev_temp >= temp_now)) {
|
|
battery->temp_control = false;
|
|
}
|
|
|
|
pr_info("%s : prev_temp(%d), temp_now(%d), temp_control(%d)\n",
|
|
__func__, prev_temp, battery->temperature, battery->temp_control);
|
|
}
|
|
#endif
|
|
|
|
static void sec_bat_get_temperature_info(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
switch (battery->pdata->thermal_source) {
|
|
case SEC_BATTERY_THERMAL_SOURCE_FG:
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_TEMP, value);
|
|
battery->temperature = value.intval;
|
|
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_TEMP_AMBIENT, value);
|
|
battery->temper_amb = value.intval;
|
|
break;
|
|
case SEC_BATTERY_THERMAL_SOURCE_CALLBACK:
|
|
if (battery->pdata->get_temperature_callback) {
|
|
battery->pdata->get_temperature_callback(
|
|
POWER_SUPPLY_PROP_TEMP, &value);
|
|
battery->temperature = value.intval;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_TEMP, value);
|
|
|
|
battery->pdata->get_temperature_callback(
|
|
POWER_SUPPLY_PROP_TEMP_AMBIENT, &value);
|
|
battery->temper_amb = value.intval;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_TEMP_AMBIENT, value);
|
|
}
|
|
break;
|
|
case SEC_BATTERY_THERMAL_SOURCE_ADC:
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_TEMP, &value);
|
|
battery->temperature = value.intval;
|
|
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_TEMP_AMBIENT, &value);
|
|
battery->temper_amb = value.intval;
|
|
|
|
#if defined(CONFIG_ABNORMAL_BAT_THM_WA)
|
|
sec_bat_control_temperature(battery);
|
|
battery->prev_bat_temp = battery->temperature;
|
|
#endif
|
|
|
|
if (battery->pdata->usb_thermal_source) {
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_USB_TEMP, &value);
|
|
battery->usb_temp = value.intval;
|
|
}
|
|
|
|
switch (battery->pdata->chg_thermal_source) {
|
|
case SEC_CHARGER_THERMAL_SOURCE_FG:
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_TEMP, value);
|
|
battery->chg_temp = value.intval;
|
|
break;
|
|
case SEC_CHARGER_THERMAL_SOURCE_ADC:
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_CHG_TEMP, &value);
|
|
battery->chg_temp = value.intval;
|
|
break;
|
|
default:
|
|
value.intval = 0;
|
|
break;
|
|
}
|
|
|
|
if (battery->pdata->wpc_thermal_source) {
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_WPC_TEMP, &value);
|
|
battery->wpc_temp = value.intval;
|
|
battery->coil_temp = value.intval;
|
|
}
|
|
|
|
if (battery->pdata->slave_thermal_source) {
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_SLAVE_CHG_TEMP, &value);
|
|
battery->slave_chg_temp = value.intval;
|
|
|
|
/* set temperature */
|
|
value.intval = ((battery->slave_chg_temp) << 16) | (battery->chg_temp);
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_TEMP, value);
|
|
}
|
|
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
if (battery->temperature_test_battery > -300 && battery->temperature_test_battery < 3000) {
|
|
pr_info("%s : battery temperature test %d\n", __func__, battery->temperature_test_battery);
|
|
battery->temperature = battery->temperature_test_battery;
|
|
}
|
|
if (battery->temperature_test_usb > -300 && battery->temperature_test_usb < 3000) {
|
|
pr_info("%s : usb temperature test %d\n", __func__, battery->temperature_test_usb);
|
|
battery->usb_temp = battery->temperature_test_usb;
|
|
}
|
|
if (battery->temperature_test_wpc > -300 && battery->temperature_test_wpc < 3000) {
|
|
pr_info("%s : wpc temperature test %d\n", __func__, battery->temperature_test_wpc);
|
|
battery->wpc_temp = battery->temperature_test_wpc;
|
|
battery->coil_temp = battery->temperature_test_wpc;
|
|
}
|
|
if (battery->temperature_test_chg > -300 && battery->temperature_test_chg < 3000) {
|
|
pr_info("%s : chg temperature test %d\n", __func__, battery->temperature_test_chg);
|
|
battery->chg_temp = battery->temperature_test_chg;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
if (battery->temperature <= (-200)) {
|
|
value.intval = battery->usb_temp;
|
|
} else {
|
|
value.intval = battery->temperature;
|
|
}
|
|
#else
|
|
value.intval = battery->temperature;
|
|
#endif
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_TEMP, value);
|
|
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_TEMP_AMBIENT, value);
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void sec_bat_get_battery_info(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_NOW, value);
|
|
battery->voltage_now = value.intval;
|
|
|
|
value.intval = SEC_BATTERY_VOLTAGE_AVERAGE;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_AVG, value);
|
|
battery->voltage_avg = value.intval;
|
|
|
|
/* Do not call it to reduce time after cable_work, this funtion call FG full log*/
|
|
if (!(battery->current_event & SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL)) {
|
|
value.intval = SEC_BATTERY_VOLTAGE_OCV;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_AVG, value);
|
|
battery->voltage_ocv = value.intval;
|
|
}
|
|
|
|
value.intval = SEC_BATTERY_CURRENT_MA;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_NOW, value);
|
|
battery->current_now = value.intval;
|
|
|
|
value.intval = SEC_BATTERY_CURRENT_MA;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_AVG, value);
|
|
battery->current_avg = value.intval;
|
|
|
|
/* input current limit in charger */
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
battery->current_max = value.intval;
|
|
|
|
/* check abnormal status for wireless charging */
|
|
if (!(battery->current_event & SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL) &&
|
|
is_wireless_type(battery->cable_type)) {
|
|
value.intval = battery->capacity;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
}
|
|
|
|
sec_bat_get_temperature_info(battery);
|
|
|
|
/* To get SOC value (NOT raw SOC), need to reset value */
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
/* if the battery status was full, and SOC wasn't 100% yet,
|
|
then ignore FG SOC, and report (previous SOC +1)% */
|
|
battery->capacity = value.intval;
|
|
|
|
dev_info(battery->dev,
|
|
"%s:Vnow(%dmV),Inow(%dmA),Imax(%dmA),Ichg(%dmA),SOC(%d%%),Tbat(%d), Tusb(%d), Tchg(%d),Twpc(%d)"
|
|
"\n", __func__,
|
|
battery->voltage_now, battery->current_now,
|
|
battery->current_max, battery->charging_current,
|
|
battery->capacity, battery->temperature,
|
|
battery->usb_temp, battery->chg_temp, battery->wpc_temp
|
|
);
|
|
dev_dbg(battery->dev,
|
|
"%s,Vavg(%dmV),Vocv(%dmV),Tamb(%d),"
|
|
"Iavg(%dmA),Iadc(%d)\n",
|
|
battery->present ? "Connected" : "Disconnected",
|
|
battery->voltage_avg, battery->voltage_ocv,
|
|
battery->temper_amb,
|
|
battery->current_avg, battery->current_adc
|
|
);
|
|
|
|
sec_debug_set_extra_info_batt(battery->capacity, battery->voltage_avg,
|
|
battery->temperature, battery->current_avg);
|
|
}
|
|
|
|
static void sec_bat_polling_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(
|
|
work, struct sec_battery_info, polling_work.work);
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
dev_dbg(battery->dev, "%s: Activated\n", __func__);
|
|
}
|
|
|
|
static void sec_bat_program_alarm(
|
|
struct sec_battery_info *battery, int seconds)
|
|
{
|
|
alarm_start(&battery->polling_alarm,
|
|
ktime_add(battery->last_poll_time, ktime_set(seconds, 0)));
|
|
}
|
|
|
|
static unsigned int sec_bat_get_polling_time(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
if (battery->status ==
|
|
POWER_SUPPLY_STATUS_FULL)
|
|
battery->polling_time =
|
|
battery->pdata->polling_time[
|
|
POWER_SUPPLY_STATUS_CHARGING];
|
|
else
|
|
battery->polling_time =
|
|
battery->pdata->polling_time[
|
|
battery->status];
|
|
|
|
battery->polling_short = true;
|
|
|
|
switch (battery->status) {
|
|
case POWER_SUPPLY_STATUS_CHARGING:
|
|
if (battery->polling_in_sleep)
|
|
battery->polling_short = false;
|
|
break;
|
|
case POWER_SUPPLY_STATUS_DISCHARGING:
|
|
if (battery->polling_in_sleep && (battery->ps_enable != true)) {
|
|
battery->polling_time =
|
|
battery->pdata->polling_time[
|
|
SEC_BATTERY_POLLING_TIME_SLEEP];
|
|
} else
|
|
battery->polling_time =
|
|
battery->pdata->polling_time[
|
|
battery->status];
|
|
if (!battery->wc_enable) {
|
|
battery->polling_time = battery->pdata->polling_time[
|
|
SEC_BATTERY_POLLING_TIME_CHARGING];
|
|
pr_info("%s: wc_enable is false, polling time is 30sec\n", __func__);
|
|
}
|
|
battery->polling_short = false;
|
|
break;
|
|
case POWER_SUPPLY_STATUS_FULL:
|
|
if (battery->polling_in_sleep) {
|
|
if (!(battery->pdata->full_condition_type &
|
|
SEC_BATTERY_FULL_CONDITION_NOSLEEPINFULL) &&
|
|
battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_NONE) {
|
|
battery->polling_time =
|
|
battery->pdata->polling_time[
|
|
SEC_BATTERY_POLLING_TIME_SLEEP];
|
|
}
|
|
battery->polling_short = false;
|
|
} else {
|
|
if (battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_NONE)
|
|
battery->polling_short = false;
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_STATUS_NOT_CHARGING:
|
|
if ((battery->health == POWER_SUPPLY_HEALTH_OVERVOLTAGE ||
|
|
(battery->health == POWER_SUPPLY_HEALTH_UNDERVOLTAGE)) &&
|
|
(battery->health_check_count > 0)) {
|
|
battery->health_check_count--;
|
|
battery->polling_time = 1;
|
|
battery->polling_short = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (battery->polling_short)
|
|
return battery->pdata->polling_time[
|
|
SEC_BATTERY_POLLING_TIME_BASIC];
|
|
/* set polling time to 46s to reduce current noise on wc */
|
|
else if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS &&
|
|
battery->status == POWER_SUPPLY_STATUS_CHARGING)
|
|
battery->polling_time = 46;
|
|
|
|
return battery->polling_time;
|
|
}
|
|
|
|
static bool sec_bat_is_short_polling(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
/* Change the full and short monitoring sequence
|
|
* Originally, full monitoring was the last time of polling_count
|
|
* But change full monitoring to first time
|
|
* because temperature check is too late
|
|
*/
|
|
if (!battery->polling_short || battery->polling_count == 1)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static void sec_bat_update_polling_count(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
/* do NOT change polling count in sleep
|
|
* even though it is short polling
|
|
* to keep polling count along sleep/wakeup
|
|
*/
|
|
if (battery->polling_short && battery->polling_in_sleep)
|
|
return;
|
|
|
|
if (battery->polling_short &&
|
|
((battery->polling_time /
|
|
battery->pdata->polling_time[
|
|
SEC_BATTERY_POLLING_TIME_BASIC])
|
|
> battery->polling_count))
|
|
battery->polling_count++;
|
|
else
|
|
battery->polling_count = 1; /* initial value = 1 */
|
|
}
|
|
|
|
static void sec_bat_set_polling(
|
|
struct sec_battery_info *battery)
|
|
{
|
|
unsigned int polling_time_temp = 0;
|
|
|
|
dev_dbg(battery->dev, "%s: Start\n", __func__);
|
|
|
|
polling_time_temp = sec_bat_get_polling_time(battery);
|
|
|
|
dev_info(battery->dev,
|
|
"%s: Status:%s, Sleep:%s, Charging:%s, Short Poll:%s\n",
|
|
__func__, sec_bat_status_str[battery->status],
|
|
battery->polling_in_sleep ? "Yes" : "No",
|
|
(battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_NONE) ? "No" : "Yes",
|
|
battery->polling_short ? "Yes" : "No");
|
|
dev_info(battery->dev,
|
|
"%s: Polling time %d/%d sec.\n", __func__,
|
|
battery->polling_short ?
|
|
(polling_time_temp * battery->polling_count) :
|
|
polling_time_temp, battery->polling_time);
|
|
|
|
/* To sync with log above,
|
|
* change polling count after log is displayed
|
|
* Do NOT update polling count in initial monitor
|
|
*/
|
|
if (!battery->pdata->monitor_initial_count)
|
|
sec_bat_update_polling_count(battery);
|
|
else
|
|
dev_dbg(battery->dev,
|
|
"%s: Initial monitor %d times left.\n", __func__,
|
|
battery->pdata->monitor_initial_count);
|
|
|
|
switch (battery->pdata->polling_type) {
|
|
case SEC_BATTERY_MONITOR_WORKQUEUE:
|
|
if (battery->pdata->monitor_initial_count) {
|
|
battery->pdata->monitor_initial_count--;
|
|
schedule_delayed_work(&battery->polling_work, HZ);
|
|
} else
|
|
schedule_delayed_work(&battery->polling_work,
|
|
polling_time_temp * HZ);
|
|
break;
|
|
case SEC_BATTERY_MONITOR_ALARM:
|
|
battery->last_poll_time = ktime_get_boottime();
|
|
|
|
if (battery->pdata->monitor_initial_count) {
|
|
battery->pdata->monitor_initial_count--;
|
|
sec_bat_program_alarm(battery, 1);
|
|
} else
|
|
sec_bat_program_alarm(battery, polling_time_temp);
|
|
break;
|
|
case SEC_BATTERY_MONITOR_TIMER:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dev_dbg(battery->dev, "%s: End\n", __func__);
|
|
}
|
|
|
|
/* OTG during HV wireless charging or sleep mode have 4.5W normal wireless charging UI */
|
|
static bool sec_bat_hv_wc_normal_mode_check(struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
if (value.intval || sleep_mode) {
|
|
pr_info("%s: otg(%d), sleep_mode(%d)\n", __func__, value.intval, sleep_mode);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
static void sec_bat_swelling_fullcharged_check(struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
int topoff_current = battery->pdata->full_check_current_1st;
|
|
|
|
switch (battery->pdata->full_check_type_2nd) {
|
|
case SEC_BATTERY_FULLCHARGED_FG_CURRENT:
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_MODE)
|
|
topoff_current = (topoff_current > battery->pdata->swelling_low_temp_topoff) ?
|
|
battery->pdata->swelling_low_temp_topoff : topoff_current;
|
|
else if (battery->current_event & SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING)
|
|
topoff_current = (topoff_current > battery->pdata->swelling_high_temp_topoff) ?
|
|
battery->pdata->swelling_high_temp_topoff : topoff_current;
|
|
|
|
if ((battery->current_now > 0 && battery->current_now < topoff_current) &&
|
|
(battery->current_avg > 0 && battery->current_avg < topoff_current) &&
|
|
(((battery->pdata->swelling_drop_float_voltage / battery->pdata->chg_float_voltage_conv) - 100)
|
|
< battery->voltage_now)) {
|
|
value.intval = POWER_SUPPLY_STATUS_FULL;
|
|
}
|
|
break;
|
|
default:
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
break;
|
|
}
|
|
|
|
if (value.intval == POWER_SUPPLY_STATUS_FULL) {
|
|
battery->swelling_full_check_cnt++;
|
|
pr_info("%s: Swelling mode full-charged check (%d)\n",
|
|
__func__, battery->swelling_full_check_cnt);
|
|
} else
|
|
battery->swelling_full_check_cnt = 0;
|
|
|
|
if (battery->swelling_full_check_cnt >=
|
|
battery->pdata->full_check_count) {
|
|
battery->swelling_full_check_cnt = 0;
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->is_recharging = false;
|
|
battery->swelling_mode = SWELLING_MODE_FULL;
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
battery->expired_time = battery->pdata->expired_time;
|
|
battery->prev_safety_time = 0;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_SWELLING_FULL_CNT]++;
|
|
battery->cisd.data[CISD_DATA_SWELLING_FULL_CNT_PER_DAY]++;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
static void sec_bat_calc_time_to_full(struct sec_battery_info * battery)
|
|
{
|
|
if (delayed_work_pending(&battery->timetofull_work)) {
|
|
pr_info("%s: keep time_to_full(%5d sec)\n", __func__, battery->timetofull);
|
|
} else if (battery->status == POWER_SUPPLY_STATUS_CHARGING ||
|
|
(battery->status == POWER_SUPPLY_STATUS_FULL && battery->capacity != 100)) {
|
|
union power_supply_propval value = {0, };
|
|
int charge = 0;
|
|
|
|
if (is_hv_wire_12v_type(battery->cable_type) ||
|
|
battery->max_charge_power >= (battery->pdata->pd_charging_charge_power + 5000)) { /* 20000mW */
|
|
charge = battery->pdata->ttf_hv_12v_charge_current;
|
|
} else if (is_hv_wire_type(battery->cable_type) ||
|
|
/* if max_charge_power could support over than max_charging_current, calculate based on ttf_hv_charge_current */
|
|
battery->max_charge_power >= (battery->pdata->max_charging_current * 5)) {
|
|
charge = battery->pdata->ttf_hv_charge_current;
|
|
} else if (is_hv_wireless_type(battery->cable_type) ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_PREPARE_WIRELESS_HV) {
|
|
if (sec_bat_hv_wc_normal_mode_check(battery))
|
|
charge = battery->pdata->ttf_wireless_charge_current;
|
|
else
|
|
charge = battery->pdata->ttf_hv_wireless_charge_current;
|
|
} else if (is_nv_wireless_type(battery->cable_type)) {
|
|
charge = battery->pdata->ttf_wireless_charge_current;
|
|
} else {
|
|
charge = battery->max_charge_power / 5;
|
|
}
|
|
value.intval = charge;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, value);
|
|
dev_info(battery->dev, "%s: T: %5d sec, passed time: %5ld, current: %d\n",
|
|
__func__, value.intval, battery->charging_passed_time, charge);
|
|
battery->timetofull = value.intval;
|
|
} else {
|
|
battery->timetofull = -1;
|
|
}
|
|
}
|
|
|
|
static void sec_bat_time_to_full_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, timetofull_work.work);
|
|
union power_supply_propval value = {0, };
|
|
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
battery->current_max = value.intval;
|
|
|
|
value.intval = SEC_BATTERY_CURRENT_MA;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_NOW, value);
|
|
battery->current_now = value.intval;
|
|
|
|
value.intval = SEC_BATTERY_CURRENT_MA;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_AVG, value);
|
|
battery->current_avg = value.intval;
|
|
|
|
sec_bat_calc_time_to_full(battery);
|
|
dev_info(battery->dev, "%s:\n", __func__);
|
|
if (battery->voltage_now > 0)
|
|
battery->voltage_now--;
|
|
|
|
power_supply_changed(battery->psy_bat);
|
|
}
|
|
#endif
|
|
|
|
extern bool get_usb_enumeration_state(void);
|
|
/* To display slow charging when usb charging 100MA*/
|
|
static void sec_bat_check_slowcharging_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, slowcharging_work.work);
|
|
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
if (battery->pdic_info.sink_status.rp_currentlvl == RP_CURRENT_LEVEL_DEFAULT &&
|
|
battery->cable_type == SEC_BATTERY_CABLE_USB) {
|
|
#else
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_USB) {
|
|
#endif
|
|
|
|
if (!get_usb_enumeration_state() &&
|
|
(battery->current_event & SEC_BAT_CURRENT_EVENT_USB_100MA)) {
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_TIMEOUT_OPEN_TYPE, 0);
|
|
battery->max_charge_power = battery->input_voltage * battery->current_max;
|
|
}
|
|
}
|
|
|
|
dev_info(battery->dev, "%s:\n", __func__);
|
|
}
|
|
|
|
static void sec_bat_wc_cv_mode_check(struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
pr_info("%s: battery->wc_cv_mode = %d\n", __func__, battery->wc_cv_mode);
|
|
|
|
if (battery->capacity >= battery->pdata->wireless_cc_cv) {
|
|
pr_info("%s: 4.5W WC Changed Vout input current limit\n", __func__);
|
|
battery->wc_cv_mode = true;
|
|
sec_bat_set_charging_current(battery);
|
|
value.intval = WIRELESS_VOUT_CC_CV_VOUT; // 5.5V
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
value.intval = WIRELESS_VRECT_ADJ_ROOM_5; // 80mv
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
if ((battery->cable_type == SEC_BATTERY_CABLE_WIRELESS ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_STAND ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK_TA)) {
|
|
value.intval = WIRELESS_CLAMP_ENABLE;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
}
|
|
/* Change FOD values for CV mode */
|
|
value.intval = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
}
|
|
}
|
|
|
|
static void sec_bat_siop_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, siop_work.work);
|
|
#if 0
|
|
#if defined(CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE)
|
|
if (battery->siop_event == SIOP_EVENT_WPC_CALL_START) {
|
|
value.intval = battery->siop_event;
|
|
pr_info("%s : set current by siop event(%d)\n",__func__, battery->siop_event);
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, value);
|
|
if (battery->capacity >= battery->pdata->wireless_cc_cv) {
|
|
pr_info("%s SIOP EVENT CALL START.\n", __func__);
|
|
value.intval = WIRELESS_VOUT_CV_CALL;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
} else {
|
|
pr_info("%s SIOP EVENT CALL START.\n", __func__);
|
|
value.intval = WIRELESS_VOUT_CC_CALL;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
}
|
|
wake_unlock(&battery->siop_wake_lock);
|
|
return;
|
|
} else if (battery->siop_event == SIOP_EVENT_WPC_CALL_END) {
|
|
battery->siop_event = 0;
|
|
value.intval = WIRELESS_VOUT_5V;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
}
|
|
#endif
|
|
#endif
|
|
pr_info("%s : set current by siop level(%d)\n",__func__, battery->siop_level);
|
|
|
|
sec_bat_set_charging_current(battery);
|
|
wake_unlock(&battery->siop_wake_lock);
|
|
}
|
|
|
|
static void sec_bat_siop_level_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, siop_level_work.work);
|
|
|
|
if (battery->siop_prev_event != battery->siop_event) {
|
|
wake_unlock(&battery->siop_level_wake_lock);
|
|
return;
|
|
}
|
|
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->siop_work, 0);
|
|
}
|
|
else
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->siop_work, 0);
|
|
|
|
wake_lock(&battery->siop_wake_lock);
|
|
wake_unlock(&battery->siop_level_wake_lock);
|
|
}
|
|
|
|
static void sec_bat_wc_headroom_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, wc_headroom_work.work);
|
|
union power_supply_propval value = {0, };
|
|
|
|
/* The default headroom is high, because initial wireless charging state is unstable.
|
|
After 10sec wireless charging, however, recover headroom level to avoid chipset damage */
|
|
if (battery->wc_status != SEC_WIRELESS_PAD_NONE) {
|
|
/* When the capacity is higher than 99, and the device is in 5V wireless charging state,
|
|
then Vrect headroom has to be headroom_2.
|
|
Refer to the sec_bat_siop_work function. */
|
|
if (battery->capacity < 99 && battery->status != POWER_SUPPLY_STATUS_FULL) {
|
|
if (is_nv_wireless_type(battery->cable_type)) {
|
|
if (battery->capacity < battery->pdata->wireless_cc_cv)
|
|
value.intval = WIRELESS_VRECT_ADJ_ROOM_4; /* WPC 4.5W, Vrect Room 30mV */
|
|
else
|
|
value.intval = WIRELESS_VRECT_ADJ_ROOM_5; /* WPC 4.5W, Vrect Room 80mV */
|
|
} else if (is_hv_wireless_type(battery->cable_type)) {
|
|
value.intval = WIRELESS_VRECT_ADJ_ROOM_5;
|
|
} else {
|
|
value.intval = WIRELESS_VRECT_ADJ_OFF;
|
|
}
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
pr_info("%s: Changed Vrect adjustment from Rx activation(10seconds)", __func__);
|
|
}
|
|
if (is_nv_wireless_type(battery->cable_type))
|
|
sec_bat_wc_cv_mode_check(battery);
|
|
}
|
|
wake_unlock(&battery->wc_headroom_wake_lock);
|
|
}
|
|
|
|
static void sec_bat_siop_event_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, siop_event_work.work);
|
|
|
|
union power_supply_propval value = {0, };
|
|
|
|
if (battery->cable_type != SEC_BATTERY_CABLE_WIRELESS_PACK &&
|
|
battery->cable_type != SEC_BATTERY_CABLE_WIRELESS_PACK_TA) {
|
|
battery->siop_prev_event = battery->siop_event;
|
|
wake_unlock(&battery->siop_event_wake_lock);
|
|
return;
|
|
}
|
|
|
|
if (!(battery->siop_prev_event & SIOP_EVENT_WPC_CALL) && (battery->siop_event & SIOP_EVENT_WPC_CALL)) {
|
|
pr_info("%s : set current by siop event(%d)\n",__func__, battery->siop_event);
|
|
if (battery->capacity >= battery->pdata->wireless_cc_cv) {
|
|
pr_info("%s SIOP EVENT CALL CV START.\n", __func__);
|
|
value.intval = WIRELESS_VOUT_CV_CALL;
|
|
} else {
|
|
pr_info("%s SIOP EVENT CALL CC START.\n", __func__);
|
|
value.intval = WIRELESS_VOUT_CC_CALL;
|
|
}
|
|
/* set current first */
|
|
sec_bat_set_charging_current(battery);
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
} else if ((battery->siop_prev_event & SIOP_EVENT_WPC_CALL) && !(battery->siop_event & SIOP_EVENT_WPC_CALL)) {
|
|
if (battery->wc_cv_mode)
|
|
value.intval = WIRELESS_VOUT_CC_CV_VOUT; // 5.5V
|
|
else
|
|
value.intval = WIRELESS_VOUT_5V;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
wake_lock(&battery->siop_level_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->siop_level_work, 0);
|
|
}
|
|
battery->siop_prev_event = battery->siop_event;
|
|
wake_unlock(&battery->siop_event_wake_lock);
|
|
}
|
|
|
|
#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE)
|
|
static void sec_bat_fw_update_work(struct sec_battery_info *battery, int mode)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
dev_info(battery->dev, "%s\n", __func__);
|
|
|
|
wake_lock_timeout(&battery->vbus_wake_lock, HZ * 10);
|
|
|
|
switch (mode) {
|
|
case SEC_WIRELESS_RX_SDCARD_MODE:
|
|
case SEC_WIRELESS_RX_BUILT_IN_MODE:
|
|
value.intval = mode;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL, value);
|
|
break;
|
|
case SEC_WIRELESS_TX_ON_MODE:
|
|
value.intval = true;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value);
|
|
|
|
value.intval = mode;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL, value);
|
|
|
|
break;
|
|
case SEC_WIRELESS_TX_OFF_MODE:
|
|
value.intval = false;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void sec_bat_fw_init_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, fw_init_work.work);
|
|
|
|
union power_supply_propval value = {0, };
|
|
int uno_status = 0, wpc_det = 0;
|
|
|
|
dev_info(battery->dev, "%s\n", __func__);
|
|
|
|
wpc_det = gpio_get_value(battery->pdata->wpc_det);
|
|
|
|
pr_info("%s wpc_det = %d\n", __func__, wpc_det);
|
|
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value);
|
|
uno_status = value.intval;
|
|
pr_info("%s uno = %d\n", __func__, uno_status);
|
|
|
|
if (!uno_status && !wpc_det) {
|
|
pr_info("%s uno on\n", __func__);
|
|
value.intval = true;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value);
|
|
}
|
|
|
|
value.intval = SEC_WIRELESS_RX_INIT;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL, value);
|
|
|
|
if (!uno_status && !wpc_det) {
|
|
pr_info("%s uno off\n", __func__);
|
|
value.intval = false;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value);
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
static int sec_bat_parse_dt(struct device *dev, struct sec_battery_info *battery);
|
|
static void sec_bat_update_data_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, batt_data_work.work);
|
|
|
|
sec_battery_update_data(battery->data_path);
|
|
wake_unlock(&battery->batt_data_wake_lock);
|
|
}
|
|
#endif
|
|
|
|
static void sec_bat_misc_event_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, misc_event_work.work);
|
|
int xor_misc_event = battery->prev_misc_event ^ battery->misc_event;
|
|
|
|
if ((xor_misc_event & (BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE |
|
|
BATT_MISC_EVENT_HICCUP_TYPE)) &&
|
|
(battery->cable_type == SEC_BATTERY_CABLE_NONE)) {
|
|
if (battery->misc_event & (BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE |
|
|
BATT_MISC_EVENT_HICCUP_TYPE)) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
} else if (battery->prev_misc_event & (BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE |
|
|
BATT_MISC_EVENT_HICCUP_TYPE)) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
}
|
|
}
|
|
|
|
pr_info("%s: change misc event(0x%x --> 0x%x)\n",
|
|
__func__, battery->prev_misc_event, battery->misc_event);
|
|
battery->prev_misc_event = battery->misc_event;
|
|
wake_unlock(&battery->misc_event_wake_lock);
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
}
|
|
|
|
static void sec_bat_calculate_safety_time(struct sec_battery_info *battery)
|
|
{
|
|
unsigned long long expired_time = battery->expired_time;
|
|
struct timespec ts = {0, };
|
|
int curr = 0;
|
|
int input_power = battery->current_max * battery->input_voltage * 1000;
|
|
int charging_power = battery->charging_current * (battery->pdata->chg_float_voltage / battery->pdata->chg_float_voltage_conv);
|
|
static int discharging_cnt = 0;
|
|
|
|
if (battery->current_avg < 0) {
|
|
discharging_cnt++;
|
|
} else {
|
|
discharging_cnt = 0;
|
|
}
|
|
|
|
if (discharging_cnt >= 5) {
|
|
battery->expired_time = battery->pdata->expired_time;
|
|
battery->prev_safety_time = 0;
|
|
pr_info("%s : SAFETY TIME RESET! DISCHARGING CNT(%d)\n",
|
|
__func__, discharging_cnt);
|
|
discharging_cnt = 0;
|
|
return;
|
|
} else if (battery->lcd_status && battery->stop_timer) {
|
|
battery->prev_safety_time = 0;
|
|
return;
|
|
}
|
|
|
|
get_monotonic_boottime(&ts);
|
|
|
|
if (ts.tv_sec == battery->prev_safety_time) {
|
|
goto safety_time_end;
|
|
}
|
|
|
|
if (battery->prev_safety_time == 0) {
|
|
battery->prev_safety_time = ts.tv_sec;
|
|
}
|
|
|
|
if (input_power > charging_power) {
|
|
curr = battery->charging_current;
|
|
} else {
|
|
curr = input_power / (battery->pdata->chg_float_voltage / battery->pdata->chg_float_voltage_conv);
|
|
curr = (curr * 9) / 10;
|
|
}
|
|
|
|
if (battery->lcd_status && !battery->stop_timer) {
|
|
battery->stop_timer = true;
|
|
} else if (!battery->lcd_status && battery->stop_timer) {
|
|
battery->stop_timer = false;
|
|
}
|
|
|
|
pr_info("%s : EXPIRED_TIME(%llu), IP(%d), CP(%d), CURR(%d), STANDARD(%d)\n",
|
|
__func__, expired_time, input_power, charging_power, curr, battery->pdata->standard_curr);
|
|
|
|
if (curr == 0)
|
|
return;
|
|
else if (curr > battery->pdata->standard_curr)
|
|
curr = battery->pdata->standard_curr;
|
|
|
|
expired_time = (expired_time * battery->pdata->standard_curr) / curr;
|
|
|
|
pr_info("%s : CAL_EXPIRED_TIME(%llu) TIME NOW(%ld) TIME PREV(%ld)\n",
|
|
__func__, expired_time, ts.tv_sec, battery->prev_safety_time);
|
|
|
|
if (expired_time <= ((ts.tv_sec - battery->prev_safety_time) * 1000))
|
|
expired_time = 0;
|
|
else
|
|
expired_time -= ((ts.tv_sec - battery->prev_safety_time) * 1000);
|
|
|
|
battery->cal_safety_time = expired_time;
|
|
expired_time = (expired_time * curr) / battery->pdata->standard_curr;
|
|
|
|
battery->expired_time = expired_time;
|
|
battery->prev_safety_time = ts.tv_sec;
|
|
|
|
safety_time_end:
|
|
pr_info("%s : REMAIN_TIME(%ld) CAL_REMAIN_TIME(%ld)\n",
|
|
__func__, battery->expired_time, battery->cal_safety_time);
|
|
}
|
|
|
|
#if defined(CONFIG_FG_FULLCAP_FROM_BATTERY)
|
|
static void sec_bat_measure_capacity(struct sec_battery_info *battery, struct timespec c_ts)
|
|
{
|
|
static struct timespec old_ts = {0, };
|
|
struct capacity_measure_info * info = &(battery->capacity_info);
|
|
unsigned long time_diff = c_ts.tv_sec - old_ts.tv_sec;
|
|
char *state[] = {
|
|
"None",
|
|
"Off",
|
|
"Measuring",
|
|
"Updating",
|
|
"Updated",
|
|
};
|
|
char data[512];
|
|
static int design_cap = 0;
|
|
|
|
if (!design_cap) {
|
|
union power_supply_propval val;
|
|
val.intval = SEC_BATTERY_CAPACITY_FULL;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, val);
|
|
design_cap = val.intval;
|
|
}
|
|
|
|
if (battery->status == POWER_SUPPLY_STATUS_DISCHARGING ||
|
|
battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
|
|
if (info->status == CAPACITY_MEASURE_UPDATING) {
|
|
int current_capacity;
|
|
current_capacity = design_cap * (info->start_soc * 3600 / 100);
|
|
info->capacity_full = info->capacity_rep + current_capacity;
|
|
info->status = CAPACITY_MEASURE_UPDATED;
|
|
sprintf(data, "full capacity: %dmAs, %dmAh, charged cap: %dmAs, start_soc: %d, asoc: %d\n",
|
|
info->capacity_full, info->capacity_full/3600, info->capacity_rep, info->start_soc,
|
|
(info->capacity_rep / 3600 * 100 * 100/((100-info->start_soc) * design_cap)));
|
|
pr_info("%s : %s\n", __func__, data);
|
|
}
|
|
if (info->status != CAPACITY_MEASURE_NONE) {
|
|
info->status = CAPACITY_MEASURE_NONE;
|
|
sprintf(data, "charger removed, battery status: %s\n", sec_bat_status_str[battery->status]);
|
|
pr_info("%s : %s\n", __func__, data);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (info->status == CAPACITY_MEASURE_OFF || info->status == CAPACITY_MEASURE_UPDATED)
|
|
return;
|
|
|
|
if (info->status == CAPACITY_MEASURE_NONE &&
|
|
battery->status == POWER_SUPPLY_STATUS_CHARGING) {
|
|
if (battery->capacity > 30) {
|
|
sprintf(data, "Do not count due to battery level(%d) high\n", battery->capacity);
|
|
pr_info("%s : %s\n", __func__, data);
|
|
info->status = CAPACITY_MEASURE_OFF;
|
|
} else {
|
|
info->status = CAPACITY_MEASURING;
|
|
info->capacity_rep = 0;
|
|
info->start_soc = battery->capacity;
|
|
old_ts = c_ts;
|
|
sprintf(data, "current_cap: %dmAs, start_soc: %d%%, cable: %s, Design Capacity: %d\n",
|
|
info->capacity_rep, info->start_soc, sec_cable_type[battery->cable_type], design_cap);
|
|
pr_info("%s : %s, time: %ld\n", __func__, data, c_ts.tv_sec);
|
|
}
|
|
return;
|
|
}
|
|
if (info->status == CAPACITY_MEASURE_NONE || time_diff == 0)
|
|
return;
|
|
|
|
info->capacity_rep += time_diff * battery->current_avg;
|
|
if (battery->status == POWER_SUPPLY_STATUS_FULL) {
|
|
info->status = CAPACITY_MEASURE_UPDATING;
|
|
if (battery->charging_mode == SEC_BATTERY_CHARGING_NONE) {
|
|
int current_capacity;
|
|
current_capacity = design_cap * (info->start_soc * 3600 / 100);
|
|
info->capacity_full = info->capacity_rep + current_capacity;
|
|
info->status = CAPACITY_MEASURE_UPDATED;
|
|
sprintf(data, "Full capacity: %dmAs, %dmAh, charged cap: %dmAs, start_soc: %d, asoc: %d\n",
|
|
info->capacity_full, info->capacity_full / 3600, info->capacity_rep, info->start_soc,
|
|
(info->capacity_rep / 3600 * 100 * 100/((100-info->start_soc) * design_cap)));
|
|
pr_info("%s : %s\n", __func__, data);
|
|
sprintf(data, "charging stopped, battery status: %s\n", sec_bat_status_str[battery->status]);
|
|
pr_info("%s : %s\n", __func__, data);
|
|
}
|
|
}
|
|
old_ts = c_ts;
|
|
pr_info("%s : current_cap: %d, status: %s, time_diff: %ld\n",
|
|
__func__, info->capacity_rep, state[info->status], time_diff);
|
|
}
|
|
#endif
|
|
|
|
static void sec_bat_monitor_work(
|
|
struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery =
|
|
container_of(work, struct sec_battery_info,
|
|
monitor_work.work);
|
|
static struct timespec old_ts = {0, };
|
|
struct timespec c_ts = {0, };
|
|
|
|
dev_dbg(battery->dev, "%s: Start\n", __func__);
|
|
c_ts = ktime_to_timespec(ktime_get_boottime());
|
|
|
|
if (!battery->wc_enable) {
|
|
pr_info("%s: wc_enable(%d), cnt(%d)\n",
|
|
__func__, battery->wc_enable, battery->wc_enable_cnt);
|
|
if (battery->wc_enable_cnt > battery->wc_enable_cnt_value) {
|
|
battery->wc_enable = true;
|
|
battery->wc_enable_cnt = 0;
|
|
if (battery->pdata->wpc_en) {
|
|
gpio_direction_output(battery->pdata->wpc_en, 0);
|
|
pr_info("%s: WC CONTROL: Enable", __func__);
|
|
}
|
|
pr_info("%s: wpc_en(%d)\n",
|
|
__func__, gpio_get_value(battery->pdata->wpc_en));
|
|
}
|
|
battery->wc_enable_cnt++;
|
|
}
|
|
|
|
/* monitor once after wakeup */
|
|
if (battery->polling_in_sleep) {
|
|
battery->polling_in_sleep = false;
|
|
if ((battery->status == POWER_SUPPLY_STATUS_DISCHARGING) &&
|
|
(battery->ps_enable != true)) {
|
|
if ((unsigned long)(c_ts.tv_sec - old_ts.tv_sec) < 10 * 60) {
|
|
union power_supply_propval value = {0, };
|
|
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_NOW, value);
|
|
battery->voltage_now = value.intval;
|
|
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
battery->capacity = value.intval;
|
|
|
|
sec_bat_get_temperature_info(battery);
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
sec_bat_cisd_check(battery);
|
|
#endif
|
|
power_supply_changed(battery->psy_bat);
|
|
pr_info("Skip monitor work(%ld, Vnow:%d(mV), SoC:%d(%%), Tbat:%d(0.1'C))\n",
|
|
c_ts.tv_sec - old_ts.tv_sec, battery->voltage_now, battery->capacity, battery->temperature);
|
|
|
|
goto skip_monitor;
|
|
}
|
|
}
|
|
}
|
|
/* update last monitor time */
|
|
old_ts = c_ts;
|
|
|
|
sec_bat_get_battery_info(battery);
|
|
|
|
#if defined(CONFIG_FG_FULLCAP_FROM_BATTERY)
|
|
sec_bat_measure_capacity(battery, c_ts);
|
|
#endif
|
|
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
sec_bat_cisd_check(battery);
|
|
#endif
|
|
|
|
#if defined(CONFIG_STEP_CHARGING)
|
|
sec_bat_check_step_charging(battery);
|
|
#endif
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
/* time to full check */
|
|
sec_bat_calc_time_to_full(battery);
|
|
#endif
|
|
|
|
/* 0. test mode */
|
|
if (battery->test_mode) {
|
|
dev_err(battery->dev, "%s: Test Mode\n", __func__);
|
|
sec_bat_do_test_function(battery);
|
|
if (battery->test_mode != 0)
|
|
goto continue_monitor;
|
|
}
|
|
|
|
/* 1. battery check */
|
|
if (!sec_bat_battery_cable_check(battery))
|
|
goto continue_monitor;
|
|
|
|
/* 2. voltage check */
|
|
if (!sec_bat_voltage_check(battery))
|
|
goto continue_monitor;
|
|
|
|
/* monitor short routine in initial monitor */
|
|
if (battery->pdata->monitor_initial_count || sec_bat_is_short_polling(battery))
|
|
goto skip_current_monitor;
|
|
|
|
/* 3. time management */
|
|
if (!sec_bat_time_management(battery))
|
|
goto continue_monitor;
|
|
|
|
/* 4. temperature check */
|
|
if (!sec_bat_temperature_check(battery))
|
|
goto continue_monitor;
|
|
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
sec_bat_swelling_check(battery);
|
|
|
|
if ((battery->swelling_mode == SWELLING_MODE_CHARGING || battery->swelling_mode == SWELLING_MODE_FULL) &&
|
|
(!battery->charging_block))
|
|
sec_bat_swelling_fullcharged_check(battery);
|
|
else
|
|
sec_bat_fullcharged_check(battery);
|
|
#else
|
|
/* 5. full charging check */
|
|
sec_bat_fullcharged_check(battery);
|
|
#endif /* CONFIG_BATTERY_SWELLING */
|
|
|
|
/* 6. additional check */
|
|
if (battery->pdata->monitor_additional_check)
|
|
battery->pdata->monitor_additional_check();
|
|
|
|
if ((battery->cable_type == SEC_BATTERY_CABLE_WIRELESS ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_STAND ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK_TA) &&
|
|
!battery->wc_cv_mode && battery->charging_passed_time > 10)
|
|
sec_bat_wc_cv_mode_check(battery);
|
|
|
|
continue_monitor:
|
|
/* clear HEATING_CONTROL*/
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL);
|
|
|
|
/* calculate safety time */
|
|
if (!battery->charging_block)
|
|
sec_bat_calculate_safety_time(battery);
|
|
|
|
/* set charging current */
|
|
sec_bat_set_charging_current(battery);
|
|
|
|
skip_current_monitor:
|
|
dev_info(battery->dev,
|
|
"%s: HLT(%d) HLR(%d) HT(%d), HR(%d), LT(%d), LR(%d), lpcharge(%d)\n",
|
|
__func__, battery->temp_highlimit_threshold, battery->temp_highlimit_recovery,
|
|
battery->temp_high_threshold, battery->temp_high_recovery,
|
|
battery->temp_low_threshold, battery->temp_low_recovery, lpcharge);
|
|
|
|
dev_info(battery->dev,
|
|
"%s: Status(%s), mode(%s), Health(%s), Cable(%s, %s, %d, %d), level(%d%%), slate_mode(%d), store_mode(%d)"
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
", HV(%s), sleep_mode(%d)"
|
|
#endif
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST_DETACHABLE)
|
|
", Cycle(%dw)"
|
|
#else
|
|
", Cycle(%d)"
|
|
#endif
|
|
#endif
|
|
"\n", __func__,
|
|
sec_bat_status_str[battery->status],
|
|
sec_bat_charging_mode_str[battery->charging_mode],
|
|
sec_bat_health_str[battery->health],
|
|
sec_cable_type[battery->cable_type],
|
|
sec_cable_type[battery->wire_status],
|
|
battery->muic_cable_type,
|
|
battery->pd_usb_attached,
|
|
battery->siop_level,
|
|
battery->slate_mode,
|
|
battery->store_mode
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
, battery->hv_chg_name, sleep_mode
|
|
#endif
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
, battery->batt_cycle
|
|
#endif
|
|
);
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
dev_info(battery->dev,
|
|
"%s: battery->stability_test(%d), battery->eng_not_full_status(%d)\n",
|
|
__func__, battery->stability_test, battery->eng_not_full_status);
|
|
#endif
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
if ((battery->cable_type != SEC_BATTERY_CABLE_NONE) && (battery->cable_type != SEC_BATTERY_CABLE_OTG)) {
|
|
#else
|
|
if ((battery->cable_type != SEC_BATTERY_CABLE_NONE) && (battery->cable_type != SEC_BATTERY_CABLE_OTG) && battery->store_mode) {
|
|
#endif
|
|
dev_info(battery->dev,
|
|
"%s: @battery->capacity = (%d), battery->status= (%d), battery->store_mode=(%d)\n",
|
|
__func__, battery->capacity, battery->status, battery->store_mode);
|
|
|
|
if (battery->capacity >= battery->pdata->store_mode_charging_max) {
|
|
int chg_mode = battery->misc_event &
|
|
(BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE | BATT_MISC_EVENT_HICCUP_TYPE) ?
|
|
SEC_BAT_CHG_MODE_BUCK_OFF : SEC_BAT_CHG_MODE_CHARGING_OFF;
|
|
/* to discharge the battery, off buck */
|
|
if (battery->capacity > battery->pdata->store_mode_charging_max)
|
|
chg_mode = SEC_BAT_CHG_MODE_BUCK_OFF;
|
|
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
sec_bat_set_charge(battery, chg_mode);
|
|
}
|
|
|
|
if ((battery->capacity <= battery->pdata->store_mode_charging_min) && (battery->status == POWER_SUPPLY_STATUS_DISCHARGING)) {
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_CHARGING);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
}
|
|
}
|
|
power_supply_changed(battery->psy_bat);
|
|
|
|
skip_monitor:
|
|
sec_bat_set_polling(battery);
|
|
|
|
if (battery->capacity <= 0 || battery->health_change)
|
|
wake_lock_timeout(&battery->monitor_wake_lock, HZ * 5);
|
|
else
|
|
wake_unlock(&battery->monitor_wake_lock);
|
|
|
|
dev_dbg(battery->dev, "%s: End\n", __func__);
|
|
|
|
return;
|
|
}
|
|
|
|
static enum alarmtimer_restart sec_bat_alarm(
|
|
struct alarm *alarm, ktime_t now)
|
|
{
|
|
struct sec_battery_info *battery = container_of(alarm,
|
|
struct sec_battery_info, polling_alarm);
|
|
|
|
dev_dbg(battery->dev,
|
|
"%s\n", __func__);
|
|
|
|
/* In wake up, monitor work will be queued in complete function
|
|
* To avoid duplicated queuing of monitor work,
|
|
* do NOT queue monitor work in wake up by polling alarm
|
|
*/
|
|
if (!battery->polling_in_sleep) {
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
dev_dbg(battery->dev, "%s: Activated\n", __func__);
|
|
}
|
|
|
|
return ALARMTIMER_NORESTART;
|
|
}
|
|
|
|
static void sec_bat_check_input_voltage(struct sec_battery_info *battery)
|
|
{
|
|
unsigned int voltage = 0;
|
|
int input_current = battery->pdata->charging_current[battery->cable_type].input_current_limit;
|
|
|
|
if (is_pd_wire_type(battery->cable_type)) {
|
|
battery->max_charge_power = battery->pd_max_charge_power;
|
|
return;
|
|
}
|
|
else if (is_hv_wire_12v_type(battery->cable_type))
|
|
voltage = SEC_INPUT_VOLTAGE_12V;
|
|
else if (is_hv_wire_9v_type(battery->cable_type))
|
|
voltage = SEC_INPUT_VOLTAGE_9V;
|
|
else if (is_hv_wireless_type(battery->cable_type) ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_PREPARE_WIRELESS_HV)
|
|
voltage = SEC_INPUT_VOLTAGE_10V;
|
|
else
|
|
voltage = SEC_INPUT_VOLTAGE_5V;
|
|
|
|
battery->input_voltage = voltage;
|
|
battery->charge_power = voltage * input_current;
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
if (battery->charge_power > battery->max_charge_power)
|
|
#endif
|
|
battery->max_charge_power = battery->charge_power;
|
|
|
|
pr_info("%s: battery->input_voltage : %dV, %dmW, %dmW\n", __func__,
|
|
battery->input_voltage, battery->charge_power, battery->max_charge_power);
|
|
}
|
|
|
|
static void sec_bat_cable_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, cable_work.work);
|
|
union power_supply_propval val = {0, };
|
|
int current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
|
|
dev_info(battery->dev, "%s: Start\n", __func__);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL,
|
|
SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL);
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
if (is_pd_wire_type(battery->wire_status)) {
|
|
pr_info("%s: check pdo num(%d <--> %d)\n", __func__,
|
|
battery->pdic_info.sink_status.selected_pdo_num,
|
|
battery->pdic_info.sink_status.current_pdo_num);
|
|
if (battery->pdic_info.sink_status.selected_pdo_num ==
|
|
battery->pdic_info.sink_status.current_pdo_num)
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SELECT_PDO);
|
|
sec_bat_get_input_current_in_power_list(battery);
|
|
sec_bat_get_charging_current_in_power_list(battery);
|
|
}
|
|
#endif
|
|
|
|
if (battery->wc_status && battery->wc_enable) {
|
|
int wireless_current, wire_current;
|
|
int temp_current_type;
|
|
|
|
if (battery->wc_status == SEC_WIRELESS_PAD_WPC)
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_WPC_HV)
|
|
current_cable_type = SEC_BATTERY_CABLE_HV_WIRELESS;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_WPC_PACK)
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS_PACK;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_WPC_PACK_TA)
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS_PACK_TA;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_WPC_STAND)
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS_STAND;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_WPC_STAND_HV)
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS_HV_STAND;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_VEHICLE)
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS_VEHICLE;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_VEHICLE_HV)
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS_HV_VEHICLE;
|
|
else if (battery->wc_status == SEC_WIRELESS_PAD_PREPARE_HV)
|
|
current_cable_type = SEC_BATTERY_CABLE_PREPARE_WIRELESS_HV;
|
|
else
|
|
current_cable_type = SEC_BATTERY_CABLE_PMA_WIRELESS;
|
|
|
|
if (current_cable_type == SEC_BATTERY_CABLE_PREPARE_WIRELESS_HV)
|
|
temp_current_type = SEC_BATTERY_CABLE_HV_WIRELESS;
|
|
else
|
|
temp_current_type = current_cable_type;
|
|
|
|
if (battery->wire_status != SEC_BATTERY_CABLE_NONE) {
|
|
wireless_current = battery->pdata->charging_current[temp_current_type].input_current_limit;
|
|
wireless_current = wireless_current * (is_hv_wireless_type(temp_current_type) ?
|
|
SEC_INPUT_VOLTAGE_9V : SEC_INPUT_VOLTAGE_5V);
|
|
if (is_pd_wire_type(battery->wire_status)) {
|
|
if (wireless_current < battery->pd_max_charge_power)
|
|
current_cable_type = battery->wire_status;
|
|
} else {
|
|
wire_current = (battery->wire_status == SEC_BATTERY_CABLE_PREPARE_TA ?
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_TA].input_current_limit :
|
|
battery->pdata->charging_current[battery->wire_status].input_current_limit);
|
|
|
|
wire_current = wire_current * (is_hv_wire_type(battery->wire_status) ?
|
|
(battery->wire_status == SEC_BATTERY_CABLE_12V_TA ? SEC_INPUT_VOLTAGE_12V : SEC_INPUT_VOLTAGE_9V)
|
|
: SEC_INPUT_VOLTAGE_5V);
|
|
pr_info("%s: wl_cur(%d), wr_cur(%d), wc_cable_type(%d), wire_cable_type(%d)\n",
|
|
__func__, wireless_current, wire_current, current_cable_type, battery->wire_status);
|
|
|
|
if (wireless_current < wire_current)
|
|
current_cable_type = battery->wire_status;
|
|
}
|
|
}
|
|
} else
|
|
current_cable_type = battery->wire_status;
|
|
|
|
if (battery->wc_status) {
|
|
/* wired charger has priority, but wireless charger exist. */
|
|
val.intval = is_wired_type(current_cable_type) ?
|
|
MFC_LDO_OFF : MFC_LDO_ON;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_EMPTY, val);
|
|
}
|
|
|
|
if (is_pd_wire_type(current_cable_type) &&
|
|
is_pd_wire_type(battery->cable_type) &&
|
|
!battery->slate_mode) {
|
|
cancel_delayed_work(&battery->afc_work);
|
|
wake_unlock(&battery->afc_wake_lock);
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_AFC);
|
|
battery->aicl_current = 0;
|
|
sec_bat_set_charging_current(battery);
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
#endif
|
|
goto end_of_cable_work;
|
|
}
|
|
|
|
/* to clear this value when cable type switched without dettach */
|
|
if ((is_wired_type(battery->cable_type) && is_wireless_type(current_cable_type)) ||
|
|
(is_wireless_type(battery->cable_type) && is_wired_type(current_cable_type)))
|
|
battery->max_charge_power = 0;
|
|
|
|
if ((current_cable_type == battery->cable_type) && !battery->slate_mode && !battery->usb_suspend_mode) {
|
|
dev_dbg(battery->dev,
|
|
"%s: Cable is NOT Changed(%d)\n",
|
|
__func__, battery->cable_type);
|
|
/* Do NOT activate cable work for NOT changed */
|
|
goto end_of_cable_work;
|
|
}
|
|
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
if ((current_cable_type == SEC_BATTERY_CABLE_NONE) ||
|
|
(battery->cable_type == SEC_BATTERY_CABLE_NONE && battery->swelling_mode == SWELLING_MODE_NONE)) {
|
|
battery->swelling_mode = SWELLING_MODE_NONE;
|
|
/* restore 4.4V float voltage */
|
|
val.intval = battery->pdata->swelling_normal_float_voltage;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
pr_info("%s: float voltage = %d\n", __func__, val.intval);
|
|
} else {
|
|
pr_info("%s: skip float voltage setting, swelling_mode(%d)\n",
|
|
__func__, battery->swelling_mode);
|
|
}
|
|
#endif
|
|
|
|
battery->cable_type = current_cable_type;
|
|
battery->wpc_vout_level = WIRELESS_VOUT_10V;
|
|
if (is_wireless_type(battery->cable_type)) {
|
|
power_supply_changed(battery->psy_bat);
|
|
/* After 10sec wireless charging, Vrect headroom has to be reduced */
|
|
wake_lock(&battery->wc_headroom_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->wc_headroom_work,
|
|
msecs_to_jiffies(10000));
|
|
}
|
|
|
|
if (battery->pdata->check_cable_result_callback)
|
|
battery->pdata->check_cable_result_callback(battery->cable_type);
|
|
/* platform can NOT get information of cable connection
|
|
* because wakeup time is too short to check uevent
|
|
* To make sure that target is wakeup
|
|
* if cable is connected and disconnected,
|
|
* activated wake lock in a few seconds
|
|
*/
|
|
wake_lock_timeout(&battery->vbus_wake_lock, HZ * 10);
|
|
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE ||
|
|
((battery->pdata->cable_check_type &
|
|
SEC_BATTERY_CABLE_CHECK_NOINCOMPATIBLECHARGE) &&
|
|
battery->cable_type == SEC_BATTERY_CABLE_UNKNOWN) ||
|
|
((battery->pdata->cable_check_type &
|
|
SEC_BATTERY_CABLE_CHECK_USBCHARGEOFF) &&
|
|
((battery->cable_type == SEC_BATTERY_CABLE_USB) ||
|
|
(battery->cable_type == SEC_BATTERY_CABLE_USB_CDP)))) {
|
|
/* initialize all status */
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->vbus_chg_by_siop = false;
|
|
battery->is_recharging = false;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.charging_end_time = 0;
|
|
battery->cisd.recharge_count = 0;
|
|
battery->cisd.charging_end_time_2 = 0;
|
|
battery->cisd.recharge_count_2 = 0;
|
|
battery->cisd.ab_vbat_check_count = 0;
|
|
battery->cisd.state &= ~CISD_STATE_OVER_VOLTAGE;
|
|
#endif
|
|
battery->input_voltage = 0;
|
|
battery->charge_power = 0;
|
|
battery->max_charge_power = 0;
|
|
battery->pd_max_charge_power = 0;
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
battery->chg_limit = false;
|
|
battery->mix_limit = false;
|
|
battery->wc_heating_start_time = 0;
|
|
battery->health = POWER_SUPPLY_HEALTH_GOOD;
|
|
cancel_delayed_work(&battery->afc_work);
|
|
wake_unlock(&battery->afc_wake_lock);
|
|
sec_bat_change_default_current(battery, SEC_BATTERY_CABLE_USB,
|
|
battery->pdata->default_usb_output_current,
|
|
battery->pdata->default_usb_output_current);
|
|
#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER) && defined(CONFIG_CCIC_NOTIFIER)
|
|
sec_bat_change_default_current(battery, SEC_BATTERY_CABLE_TA,
|
|
battery->pdata->default_ta_input_current,
|
|
battery->pdata->default_ta_output_current);
|
|
#endif
|
|
/* usb default current is 100mA before configured, but this it HW dependent! */
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_USB_100MA,
|
|
(SEC_BAT_CURRENT_EVENT_CHARGE_DISABLE |
|
|
SEC_BAT_CURRENT_EVENT_AFC |
|
|
SEC_BAT_CURRENT_EVENT_USB_SUPER |
|
|
SEC_BAT_CURRENT_EVENT_USB_100MA |
|
|
SEC_BAT_CURRENT_EVENT_VBAT_OVP |
|
|
SEC_BAT_CURRENT_EVENT_VSYS_OVP |
|
|
SEC_BAT_CURRENT_EVENT_CHG_LIMIT |
|
|
SEC_BAT_CURRENT_EVENT_SELECT_PDO));
|
|
cancel_delayed_work(&battery->slowcharging_work);
|
|
battery->wc_cv_mode = false;
|
|
battery->is_sysovlo = false;
|
|
battery->is_vbatovlo = false;
|
|
battery->is_abnormal_temp = false;
|
|
|
|
if (sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF))
|
|
goto end_of_cable_work;
|
|
} else if (battery->slate_mode) {
|
|
dev_info(battery->dev,
|
|
"%s:slate mode on\n",__func__);
|
|
battery->is_recharging = false;
|
|
battery->cable_type = SEC_BATTERY_CABLE_NONE;
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->health = POWER_SUPPLY_HEALTH_GOOD;
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
#if defined (CONFIG_ENABLE_USB_SUSPEND_STATE)
|
|
} else if (battery->usb_suspend_mode) {
|
|
dev_info(battery->dev,
|
|
"%s:usb suspend mode on\n",__func__);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
#endif
|
|
} else {
|
|
#if defined(CONFIG_EN_OOPS)
|
|
val.intval = battery->cable_type;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, val);
|
|
#endif
|
|
/* Do NOT display the charging icon when OTG or HMT_CONNECTED is enabled */
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_OTG ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_POWER_SHARING) {
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
} else if (!battery->is_sysovlo && !battery->is_vbatovlo && !battery->is_abnormal_temp &&
|
|
(!battery->charging_block || !battery->swelling_mode)) {
|
|
if (battery->pdata->full_check_type !=
|
|
SEC_BATTERY_FULLCHARGED_NONE)
|
|
battery->charging_mode =
|
|
SEC_BATTERY_CHARGING_1ST;
|
|
else
|
|
battery->charging_mode =
|
|
SEC_BATTERY_CHARGING_2ND;
|
|
|
|
if (battery->status == POWER_SUPPLY_STATUS_FULL)
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_FULL);
|
|
else
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_CHARGING);
|
|
}
|
|
|
|
if (!battery->is_sysovlo && !battery->is_vbatovlo && !battery->is_abnormal_temp)
|
|
battery->health = POWER_SUPPLY_HEALTH_GOOD;
|
|
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_TA ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_WIRELESS ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_PMA_WIRELESS) {
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
sec_bat_set_current_event(battery,
|
|
SEC_BAT_CURRENT_EVENT_AFC, SEC_BAT_CURRENT_EVENT_AFC);
|
|
#endif
|
|
} else {
|
|
cancel_delayed_work(&battery->afc_work);
|
|
wake_unlock(&battery->afc_wake_lock);
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_AFC);
|
|
}
|
|
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_OTG ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_POWER_SHARING) {
|
|
if (sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF))
|
|
goto end_of_cable_work;
|
|
} else if (!battery->is_sysovlo && !battery->is_vbatovlo && !battery->is_abnormal_temp &&
|
|
(!battery->charging_block || !battery->swelling_mode)) {
|
|
if (sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING))
|
|
goto end_of_cable_work;
|
|
}
|
|
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_USB && !lpcharge)
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->slowcharging_work,
|
|
msecs_to_jiffies(3000));
|
|
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
if (lpcharge) {
|
|
cancel_delayed_work(&battery->timetofull_work);
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_AFC) {
|
|
int work_delay = 0;
|
|
|
|
if (!is_wireless_type(battery->cable_type)) {
|
|
work_delay = battery->pdata->pre_afc_work_delay;
|
|
} else {
|
|
work_delay = battery->pdata->pre_wc_afc_work_delay;
|
|
}
|
|
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->timetofull_work, msecs_to_jiffies(work_delay));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* set online(cable type) */
|
|
val.intval = battery->cable_type;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_ONLINE, val);
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_ONLINE, val);
|
|
/* set charging current */
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_AVG, val);
|
|
battery->aicl_current = 0;
|
|
battery->input_current = val.intval;
|
|
/* to init battery type current when wireless charging -> battery case */
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE)
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, val);
|
|
if (battery->status != POWER_SUPPLY_STATUS_DISCHARGING)
|
|
sec_bat_check_input_voltage(battery);
|
|
if (battery->temperature <= battery->pdata->swelling_high_temp_recov &&
|
|
battery->temperature >= battery->pdata->swelling_low_temp_recov_1st)
|
|
sec_bat_set_charging_current(battery);
|
|
|
|
/* polling time should be reset when cable is changed
|
|
* polling_in_sleep should be reset also
|
|
* before polling time is re-calculated
|
|
* to prevent from counting 1 for events
|
|
* right after cable is connected
|
|
*/
|
|
battery->polling_in_sleep = false;
|
|
sec_bat_get_polling_time(battery);
|
|
|
|
dev_info(battery->dev,
|
|
"%s: Status:%s, Sleep:%s, Charging:%s, Short Poll:%s\n",
|
|
__func__, sec_bat_status_str[battery->status],
|
|
battery->polling_in_sleep ? "Yes" : "No",
|
|
(battery->charging_mode ==
|
|
SEC_BATTERY_CHARGING_NONE) ? "No" : "Yes",
|
|
battery->polling_short ? "Yes" : "No");
|
|
dev_info(battery->dev,
|
|
"%s: Polling time is reset to %d sec.\n", __func__,
|
|
battery->polling_time);
|
|
|
|
battery->polling_count = 1; /* initial value = 1 */
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
end_of_cable_work:
|
|
wake_unlock(&battery->cable_wake_lock);
|
|
dev_info(battery->dev, "%s: End\n", __func__);
|
|
}
|
|
|
|
static void sec_bat_afc_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, afc_work.work);
|
|
union power_supply_propval value = {0, };
|
|
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
battery->current_max = value.intval;
|
|
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_AFC) {
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_AFC);
|
|
if ((battery->wc_status != SEC_WIRELESS_PAD_NONE &&
|
|
battery->current_max >= battery->pdata->pre_wc_afc_input_current) ||
|
|
((battery->cable_type == SEC_BATTERY_CABLE_TA) &&
|
|
battery->current_max >= battery->pdata->pre_afc_input_current)) {
|
|
sec_bat_set_charging_current(battery);
|
|
}
|
|
power_supply_changed(battery->psy_bat);
|
|
}
|
|
wake_unlock(&battery->afc_wake_lock);
|
|
}
|
|
|
|
ssize_t sec_bat_show_attrs(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
const ptrdiff_t offset = attr - sec_battery_attrs;
|
|
union power_supply_propval value = {0, };
|
|
int i = 0;
|
|
int ret = 0;
|
|
|
|
switch (offset) {
|
|
case BATT_RESET_SOC:
|
|
break;
|
|
case BATT_READ_RAW_SOC:
|
|
{
|
|
value.intval =
|
|
SEC_FUELGAUGE_CAPACITY_TYPE_RAW;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
}
|
|
break;
|
|
case BATT_READ_ADJ_SOC:
|
|
break;
|
|
case BATT_TYPE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n",
|
|
battery->batt_type);
|
|
break;
|
|
case BATT_VFOCV:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->voltage_ocv);
|
|
break;
|
|
case BATT_VOL_ADC:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->inbat_adc);
|
|
break;
|
|
case BATT_VOL_ADC_CAL:
|
|
break;
|
|
case BATT_VOL_AVER:
|
|
break;
|
|
case BATT_VOL_ADC_AVER:
|
|
break;
|
|
|
|
case BATT_CURRENT_UA_NOW:
|
|
{
|
|
value.intval = SEC_BATTERY_CURRENT_UA;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_NOW, value);
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
pr_err("%s: batt_current_ua_now (%d)\n",
|
|
__func__, value.intval);
|
|
#endif
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
}
|
|
break;
|
|
case BATT_CURRENT_UA_AVG:
|
|
{
|
|
value.intval = SEC_BATTERY_CURRENT_UA;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_AVG, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
}
|
|
break;
|
|
case BATT_FILTER_CFG:
|
|
{
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_FILTER_CFG, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n",
|
|
value.intval);
|
|
}
|
|
break;
|
|
case BATT_TEMP:
|
|
switch (battery->pdata->thermal_source) {
|
|
case SEC_BATTERY_THERMAL_SOURCE_FG:
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_TEMP, value);
|
|
break;
|
|
case SEC_BATTERY_THERMAL_SOURCE_CALLBACK:
|
|
if (battery->pdata->get_temperature_callback) {
|
|
battery->pdata->get_temperature_callback(
|
|
POWER_SUPPLY_PROP_TEMP, &value);
|
|
}
|
|
break;
|
|
case SEC_BATTERY_THERMAL_SOURCE_ADC:
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_TEMP, &value);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
break;
|
|
case BATT_TEMP_ADC:
|
|
/*
|
|
If F/G is used for reading the temperature and
|
|
compensation table is used,
|
|
the raw value that isn't compensated can be read by
|
|
POWER_SUPPLY_PROP_TEMP_AMBIENT
|
|
*/
|
|
switch (battery->pdata->thermal_source) {
|
|
case SEC_BATTERY_THERMAL_SOURCE_FG:
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_TEMP_AMBIENT, value);
|
|
battery->temp_adc = value.intval;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->temp_adc);
|
|
break;
|
|
case BATT_TEMP_AVER:
|
|
break;
|
|
case BATT_TEMP_ADC_AVER:
|
|
break;
|
|
case USB_TEMP:
|
|
if (battery->pdata->usb_thermal_source) {
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_USB_TEMP, &value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case USB_TEMP_ADC:
|
|
if (battery->pdata->usb_thermal_source) {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->usb_temp_adc);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case CHG_TEMP:
|
|
switch (battery->pdata->chg_thermal_source) {
|
|
case SEC_CHARGER_THERMAL_SOURCE_FG:
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_TEMP, value);
|
|
break;
|
|
case SEC_CHARGER_THERMAL_SOURCE_ADC:
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_CHG_TEMP, &value);
|
|
break;
|
|
default:
|
|
value.intval = 0;
|
|
break;
|
|
}
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
break;
|
|
case CHG_TEMP_ADC:
|
|
if (battery->pdata->chg_thermal_source ==
|
|
SEC_CHARGER_THERMAL_SOURCE_ADC) {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->chg_temp_adc);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case SLAVE_CHG_TEMP:
|
|
if (battery->pdata->slave_thermal_source) {
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_SLAVE_CHG_TEMP, &value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case SLAVE_CHG_TEMP_ADC:
|
|
if (battery->pdata->slave_thermal_source) {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->slave_chg_temp_adc);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case BATT_VF_ADC:
|
|
if (battery->pdata->battery_check_type ==
|
|
SEC_BATTERY_CHECK_CHARGER_AND_ADC) {
|
|
sec_bat_check_vf_adc(battery);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->check_adc_value);
|
|
}
|
|
break;
|
|
case BATT_SLATE_MODE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->slate_mode);
|
|
break;
|
|
|
|
case BATT_LP_CHARGING:
|
|
if (lpcharge) {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
lpcharge ? 1 : 0);
|
|
}
|
|
break;
|
|
case SIOP_ACTIVATED:
|
|
break;
|
|
case SIOP_LEVEL:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->siop_level);
|
|
break;
|
|
case SIOP_EVENT:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->siop_event);
|
|
break;
|
|
case BATT_CHARGING_SOURCE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->cable_type);
|
|
break;
|
|
case FG_REG_DUMP:
|
|
break;
|
|
case FG_RESET_CAP:
|
|
break;
|
|
case FG_CAPACITY:
|
|
{
|
|
value.intval =
|
|
SEC_BATTERY_CAPACITY_DESIGNED;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x ",
|
|
value.intval);
|
|
|
|
value.intval =
|
|
SEC_BATTERY_CAPACITY_ABSOLUTE;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x ",
|
|
value.intval);
|
|
|
|
value.intval =
|
|
SEC_BATTERY_CAPACITY_TEMPERARY;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x ",
|
|
value.intval);
|
|
|
|
value.intval =
|
|
SEC_BATTERY_CAPACITY_CURRENT;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%04x\n",
|
|
value.intval);
|
|
}
|
|
break;
|
|
case FG_ASOC:
|
|
value.intval = -1;
|
|
{
|
|
struct power_supply *psy_fg = NULL;
|
|
psy_fg = get_power_supply_by_name(battery->pdata->fuelgauge_name);
|
|
if (!psy_fg) {
|
|
pr_err("%s: Fail to get psy (%s)\n",
|
|
__func__, battery->pdata->fuelgauge_name);
|
|
} else {
|
|
if (psy_fg->desc->get_property != NULL) {
|
|
#if defined(CONFIG_FUELGAUGE_ASOC_FROM_CYCLES)
|
|
value.intval = battery->batt_cycle;
|
|
#endif
|
|
ret = psy_fg->desc->get_property(psy_fg,
|
|
POWER_SUPPLY_PROP_ENERGY_FULL, &value);
|
|
if (ret < 0) {
|
|
pr_err("%s: Fail to %s get (%d=>%d)\n",
|
|
__func__, battery->pdata->fuelgauge_name,
|
|
POWER_SUPPLY_PROP_ENERGY_FULL, ret);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
break;
|
|
case AUTH:
|
|
break;
|
|
case CHG_CURRENT_ADC:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->current_adc);
|
|
break;
|
|
case WC_ADC:
|
|
break;
|
|
case WC_STATUS:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
is_wireless_type(battery->cable_type) ? 1: 0);
|
|
break;
|
|
case WC_ENABLE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->wc_enable);
|
|
break;
|
|
case WC_CONTROL:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->wc_enable);
|
|
break;
|
|
case WC_CONTROL_CNT:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->wc_enable_cnt_value);
|
|
break;
|
|
case LED_COVER:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->led_cover);
|
|
break;
|
|
case HV_CHARGER_STATUS:
|
|
{
|
|
int check_val = 0;
|
|
|
|
if (is_hv_wire_12v_type(battery->cable_type)) {/* 20000mW */
|
|
check_val = 2;
|
|
} else if (is_hv_wire_type(battery->cable_type)) {
|
|
check_val = 1;
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
} else if (is_pd_wire_type(battery->cable_type)) {
|
|
if (battery->pd_max_charge_power >= HV_CHARGER_STATUS_STANDARD1 &&
|
|
battery->pdic_info.sink_status.available_pdo_num > 1) {
|
|
check_val = 1;
|
|
}
|
|
#endif
|
|
} else if (battery->wire_status == SEC_BATTERY_CABLE_PREPARE_TA) {
|
|
check_val = 1;
|
|
} else if (battery->max_charge_power >= HV_CHARGER_STATUS_STANDARD2) { /* 20000mW */
|
|
check_val = 2;
|
|
} else if (battery->max_charge_power >= HV_CHARGER_STATUS_STANDARD1) { /* 12000mW */
|
|
check_val = 1;
|
|
}
|
|
|
|
pr_info("%s : HV_CHARGER_STATUS(%d), max charge power(%d)\n",
|
|
__func__, check_val, battery->max_charge_power);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", check_val);
|
|
}
|
|
break;
|
|
case HV_WC_CHARGER_STATUS:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
is_hv_wireless_type(battery->cable_type) ? 1 : 0);
|
|
break;
|
|
case HV_CHARGER_SET:
|
|
break;
|
|
case FACTORY_MODE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->factory_mode);
|
|
break;
|
|
case STORE_MODE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->store_mode);
|
|
break;
|
|
case UPDATE:
|
|
break;
|
|
case TEST_MODE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->test_mode);
|
|
break;
|
|
|
|
case BATT_EVENT_CALL:
|
|
case BATT_EVENT_2G_CALL:
|
|
case BATT_EVENT_TALK_GSM:
|
|
break;
|
|
case BATT_EVENT_3G_CALL:
|
|
case BATT_EVENT_TALK_WCDMA:
|
|
break;
|
|
case BATT_EVENT_MUSIC:
|
|
break;
|
|
case BATT_EVENT_VIDEO:
|
|
break;
|
|
case BATT_EVENT_BROWSER:
|
|
break;
|
|
case BATT_EVENT_HOTSPOT:
|
|
break;
|
|
case BATT_EVENT_CAMERA:
|
|
break;
|
|
case BATT_EVENT_CAMCORDER:
|
|
break;
|
|
case BATT_EVENT_DATA_CALL:
|
|
break;
|
|
case BATT_EVENT_WIFI:
|
|
break;
|
|
case BATT_EVENT_WIBRO:
|
|
break;
|
|
case BATT_EVENT_LTE:
|
|
break;
|
|
case BATT_EVENT_LCD:
|
|
break;
|
|
case BATT_EVENT_GPS:
|
|
break;
|
|
case BATT_EVENT:
|
|
break;
|
|
case BATT_TEMP_TABLE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i,
|
|
"%d %d %d %d %d %d %d %d\n",
|
|
battery->pdata->temp_high_threshold_normal,
|
|
battery->pdata->temp_high_recovery_normal,
|
|
battery->pdata->temp_low_threshold_normal,
|
|
battery->pdata->temp_low_recovery_normal,
|
|
battery->pdata->temp_high_threshold_lpm,
|
|
battery->pdata->temp_high_recovery_lpm,
|
|
battery->pdata->temp_low_threshold_lpm,
|
|
battery->pdata->temp_low_recovery_lpm);
|
|
break;
|
|
case BATT_HIGH_CURRENT_USB:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->is_hc_usb);
|
|
break;
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
case TEST_CHARGE_CURRENT:
|
|
{
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CURRENT_NOW, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
}
|
|
break;
|
|
#endif
|
|
case SET_STABILITY_TEST:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->stability_test);
|
|
break;
|
|
case BATT_CAPACITY_MAX:
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case BATT_INBAT_VOLTAGE:
|
|
case BATT_INBAT_VOLTAGE_OCV:
|
|
if (battery->pdata->support_fgsrc_change == true) {
|
|
int j, k, ocv, ocv_data[5];
|
|
value.intval = SEC_BAT_INBAT_FGSRC_SWITCHING_ON;
|
|
psy_do_property(battery->pdata->fgsrc_switch_name, set,
|
|
POWER_SUPPLY_EXT_PROP_INBAT_VOLTAGE_FGSRC_SWITCHING, value);
|
|
|
|
for (j = 0; j < 5; j++) {
|
|
msleep(200);
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_NOW, value);
|
|
ocv_data[j] = value.intval;
|
|
}
|
|
|
|
if (battery->is_jig_on || battery->factory_mode || factory_mode) {
|
|
value.intval = SEC_BAT_INBAT_FGSRC_SWITCHING_OFF;
|
|
psy_do_property(battery->pdata->fgsrc_switch_name, set,
|
|
POWER_SUPPLY_EXT_PROP_INBAT_VOLTAGE_FGSRC_SWITCHING, value);
|
|
}
|
|
|
|
for (j = 1; j < 5; j++) {
|
|
ocv = ocv_data[j];
|
|
k = j;
|
|
while (k > 0 && ocv_data[k-1] > ocv) {
|
|
ocv_data[k] = ocv_data[k-1];
|
|
k--;
|
|
}
|
|
ocv_data[k] = ocv;
|
|
}
|
|
|
|
for (j = 0; j < 5; j++)
|
|
pr_info("%s: %d\n", __func__, ocv_data[j]);
|
|
|
|
ocv = 0;
|
|
for (j = 1; j < 4; j++) {
|
|
ocv += ocv_data[j];
|
|
}
|
|
ret = ocv / 3;
|
|
} else {
|
|
/* run twice */
|
|
ret = (sec_bat_get_inbat_vol_by_adc(battery) +
|
|
sec_bat_get_inbat_vol_by_adc(battery)) / 2;
|
|
}
|
|
dev_info(battery->dev, "in-battery voltage ocv(%d)\n", ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_INBAT_VOLTAGE_ADC:
|
|
/* run twice */
|
|
ret = (sec_bat_get_inbat_vol_by_adc(battery) +\
|
|
sec_bat_get_inbat_vol_by_adc(battery)) / 2;
|
|
dev_info(battery->dev, "in-battery voltage adc(%d)\n", ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case CHECK_SLAVE_CHG:
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_CHECK_SLAVE_I2C, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
pr_info("%s : CHECK_SLAVE_CHG=%d\n",__func__,value.intval);
|
|
break;
|
|
case BATT_INBAT_WIRELESS_CS100:
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case HMT_TA_CONNECTED:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
(battery->cable_type == SEC_BATTERY_CABLE_HMT_CONNECTED) ? 1 : 0);
|
|
break;
|
|
case HMT_TA_CHARGE:
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
(battery->current_event & SEC_BAT_CURRENT_EVENT_CHARGE_DISABLE) ? 0 : 1);
|
|
#else
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
(battery->cable_type == SEC_BATTERY_CABLE_HMT_CHARGE) ? 1 : 0);
|
|
#endif
|
|
break;
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
case FG_CYCLE:
|
|
value.intval = SEC_BATTERY_CAPACITY_CYCLE;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
value.intval = value.intval / 100;
|
|
dev_info(battery->dev, "fg cycle(%d)\n", value.intval);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case FG_FULL_VOLTAGE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d %d\n",
|
|
battery->pdata->chg_float_voltage, battery->pdata->recharge_condition_vcell);
|
|
break;
|
|
case FG_FULLCAPNOM:
|
|
value.intval =
|
|
SEC_BATTERY_CAPACITY_AGEDCELL;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST_DETACHABLE)
|
|
case BATT_AFTER_MANUFACTURED:
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT) || defined(CONFIG_SEC_FACTORY)
|
|
case BATTERY_CYCLE:
|
|
#endif
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", battery->batt_cycle);
|
|
break;
|
|
#else
|
|
case BATTERY_CYCLE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", battery->batt_cycle);
|
|
break;
|
|
#endif
|
|
#endif
|
|
case FG_CYCLE_CHECK_VALUE:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", battery->pdata->fg_cycle_check_value);
|
|
break;
|
|
case BATT_WPC_TEMP:
|
|
if (battery->pdata->wpc_thermal_source) {
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_WPC_TEMP, &value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case BATT_WPC_TEMP_ADC:
|
|
if (battery->pdata->wpc_thermal_source) {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->wpc_temp_adc);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case BATT_COIL_TEMP:
|
|
if (battery->pdata->coil_thermal_source) {
|
|
sec_bat_get_value_by_adc(battery,
|
|
SEC_BAT_ADC_CHANNEL_WPC_TEMP, &value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case BATT_COIL_TEMP_ADC:
|
|
if (battery->pdata->coil_thermal_source) {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->coil_temp_adc);
|
|
} else {
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
0);
|
|
}
|
|
break;
|
|
case BATT_WIRELESS_MST_SWITCH_TEST:
|
|
value.intval = SEC_WIRELESS_MST_SWITCH_VERIFY;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
pr_info("%s MST switch verify. result: %x\n", __func__, value.intval);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n", value.intval);
|
|
break;
|
|
#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE)
|
|
case BATT_WIRELESS_FIRMWARE_UPDATE:
|
|
value.intval = SEC_WIRELESS_OTP_FIRM_VERIFY;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
pr_info("%s RX firmware verify. result: %d\n", __func__, value.intval);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case OTP_FIRMWARE_RESULT:
|
|
value.intval = SEC_WIRELESS_OTP_FIRM_RESULT;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case WC_IC_GRADE:
|
|
value.intval = SEC_WIRELESS_IC_GRADE;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%x ", value.intval);
|
|
|
|
value.intval = SEC_WIRELESS_IC_REVISION;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%x\n", value.intval);
|
|
break;
|
|
case OTP_FIRMWARE_VER_BIN:
|
|
value.intval = SEC_WIRELESS_OTP_FIRM_VER_BIN;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n", value.intval);
|
|
break;
|
|
case OTP_FIRMWARE_VER:
|
|
value.intval = SEC_WIRELESS_OTP_FIRM_VER;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n", value.intval);
|
|
break;
|
|
case TX_FIRMWARE_RESULT:
|
|
value.intval = SEC_WIRELESS_TX_FIRM_RESULT;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case TX_FIRMWARE_VER:
|
|
value.intval = SEC_WIRELESS_TX_FIRM_VER;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n", value.intval);
|
|
break;
|
|
case BATT_TX_STATUS:
|
|
value.intval = SEC_TX_FIRMWARE;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n", value.intval);
|
|
break;
|
|
#endif
|
|
case WC_VOUT:
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case WC_VRECT:
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_AVG, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case BATT_HV_WIRELESS_STATUS:
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case BATT_HV_WIRELESS_PAD_CTRL:
|
|
break;
|
|
case WC_OP_FREQ:
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_WIRELESS_OP_FREQ, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval);
|
|
break;
|
|
case WC_CMD_INFO:
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_WIRELESS_TX_CMD, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%02x ",
|
|
value.intval);
|
|
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_WIRELESS_TX_VAL, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "0x%02x ",
|
|
value.intval);
|
|
break;
|
|
case BATT_TUNE_FLOAT_VOLTAGE:
|
|
ret = battery->pdata->chg_float_voltage;
|
|
pr_info("%s float voltage = %d mA",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_INPUT_CHARGE_CURRENT:
|
|
ret = battery->pdata->charging_current[i].input_current_limit;
|
|
pr_info("%s input charge current = %d mA",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_FAST_CHARGE_CURRENT:
|
|
ret = battery->pdata->charging_current[i].fast_charging_current;
|
|
pr_info("%s fast charge current = %d mA",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_UI_TERM_CURRENT_1ST:
|
|
ret = battery->pdata->full_check_current_1st;
|
|
pr_info("%s ui term current = %d mA",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_UI_TERM_CURRENT_2ND:
|
|
ret = battery->pdata->full_check_current_2nd;
|
|
pr_info("%s ui term current = %d mA",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_TEMP_HIGH_NORMAL:
|
|
ret = battery->pdata->temp_high_threshold_normal;
|
|
pr_info("%s temp high normal block = %d ",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_TEMP_HIGH_REC_NORMAL:
|
|
ret = battery->pdata->temp_high_recovery_normal;
|
|
pr_info("%s temp high normal recover = %d ",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_TEMP_LOW_NORMAL:
|
|
ret = battery->pdata->temp_low_threshold_normal;
|
|
pr_info("%s temp low normal block = %d ",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_TEMP_LOW_REC_NORMAL:
|
|
ret = battery->pdata->temp_low_recovery_normal;
|
|
pr_info("%s temp low normal recover = %d ",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_CHG_TEMP_HIGH:
|
|
ret = battery->pdata->chg_high_temp;
|
|
pr_info("%s chg_high_temp = %d ",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_CHG_TEMP_REC:
|
|
ret = battery->pdata->chg_high_temp_recovery;
|
|
pr_info("%s chg_high_temp_recovery = %d ",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_CHG_LIMIT_CUR:
|
|
ret = battery->pdata->chg_charging_limit_current;
|
|
pr_info("%s chg_charging_limit_current = %d ",__func__, ret);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
ret);
|
|
break;
|
|
case BATT_TUNE_COIL_TEMP_HIGH:
|
|
break;
|
|
case BATT_TUNE_COIL_TEMP_REC:
|
|
break;
|
|
case BATT_TUNE_COIL_LIMIT_CUR:
|
|
break;
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
case BATT_UPDATE_DATA:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n",
|
|
battery->data_path ? "OK" : "NOK");
|
|
break;
|
|
#endif
|
|
case BATT_MISC_EVENT:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->misc_event);
|
|
break;
|
|
case BATT_EXT_DEV_CHG:
|
|
break;
|
|
case BATT_WDT_CONTROL:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->wdt_kick_disable);
|
|
break;
|
|
case MODE:
|
|
value.strval = NULL;
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_MULTI_CHARGER_MODE, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n",
|
|
(value.strval) ? value.strval : "master");
|
|
break;
|
|
case CHECK_PS_READY:
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
value.intval = battery->pdic_ps_rdy;
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
pr_info("%s : CHECK_PS_READY=%d\n",__func__,value.intval);
|
|
#endif
|
|
break;
|
|
case BATT_CHIP_ID:
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_CHIP_ID, value);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
value.intval);
|
|
break;
|
|
case CISD_FULLCAPREP_MAX:
|
|
{
|
|
union power_supply_propval fullcaprep_val;
|
|
#if defined(CONFIG_FG_FULLCAP_FROM_BATTERY)
|
|
struct capacity_measure_info * info = &(battery->capacity_info);
|
|
|
|
fullcaprep_val.intval = info->capacity_full / 3600;
|
|
#else
|
|
fullcaprep_val.intval = SEC_BATTERY_CAPACITY_FULL;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, fullcaprep_val);
|
|
#endif
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
fullcaprep_val.intval);
|
|
}
|
|
break;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
case CISD_DATA:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
char temp_buf[1024] = {0,};
|
|
int j = 0;
|
|
|
|
sprintf(temp_buf+strlen(temp_buf), "%d", pcisd->data[CISD_DATA_RESET_ALG]);
|
|
for (j = CISD_DATA_RESET_ALG + 1; j < CISD_DATA_MAX_PER_DAY; j++)
|
|
sprintf(temp_buf+strlen(temp_buf), " %d", pcisd->data[j]);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", temp_buf);
|
|
}
|
|
break;
|
|
case CISD_DATA_JSON:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
char temp_buf[1024] = {0,};
|
|
int j = 0;
|
|
int size = 0;
|
|
|
|
snprintf(temp_buf, sizeof(temp_buf), "\"%s\":\"%d\"",
|
|
cisd_data_str[CISD_DATA_RESET_ALG], pcisd->data[CISD_DATA_RESET_ALG]);
|
|
size = sizeof(temp_buf) - strlen(temp_buf);
|
|
|
|
for (j = CISD_DATA_RESET_ALG + 1; j < CISD_DATA_MAX; j++) {
|
|
if (battery->pdata->ignore_cisd_index[j / 32] & (0x1 << (j % 32)))
|
|
continue;
|
|
snprintf(temp_buf+strlen(temp_buf), size, ",\"%s\":\"%d\"", cisd_data_str[j], pcisd->data[j]);
|
|
size = sizeof(temp_buf) - strlen(temp_buf);
|
|
}
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", temp_buf);
|
|
}
|
|
break;
|
|
case CISD_DATA_D_JSON:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
char temp_buf[1024] = {0,};
|
|
int j = 0;
|
|
int size = 0;
|
|
|
|
snprintf(temp_buf, sizeof(temp_buf), "\"%s\":\"%d\"",
|
|
cisd_data_str_d[CISD_DATA_FULL_COUNT_PER_DAY-CISD_DATA_MAX],
|
|
pcisd->data[CISD_DATA_FULL_COUNT_PER_DAY]);
|
|
size = sizeof(temp_buf) - strlen(temp_buf);
|
|
|
|
for (j = CISD_DATA_FULL_COUNT_PER_DAY + 1; j < CISD_DATA_MAX_PER_DAY; j++) {
|
|
if (battery->pdata->ignore_cisd_index_d[(j - CISD_DATA_FULL_COUNT_PER_DAY) / 32] & (0x1 << ((j - CISD_DATA_FULL_COUNT_PER_DAY) % 32)))
|
|
continue;
|
|
snprintf(temp_buf+strlen(temp_buf), size, ",\"%s\":\"%d\"",
|
|
cisd_data_str_d[j-CISD_DATA_MAX], pcisd->data[j]);
|
|
size = sizeof(temp_buf) - strlen(temp_buf);
|
|
}
|
|
|
|
/* Clear Daily Data */
|
|
for (j = CISD_DATA_FULL_COUNT_PER_DAY; j < CISD_DATA_MAX_PER_DAY; j++)
|
|
pcisd->data[j] = 0;
|
|
|
|
pcisd->data[CISD_DATA_FULL_COUNT_PER_DAY] = 1;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MIN_PER_DAY] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MIN_PER_DAY] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CAP_MIN_PER_DAY] = 0xFFFF;
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", temp_buf);
|
|
}
|
|
break;
|
|
case CISD_WIRE_COUNT:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
pcisd->data[CISD_DATA_WIRE_COUNT]);
|
|
}
|
|
break;
|
|
case CISD_WC_DATA:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
char temp_buf[1024] = {0,};
|
|
int j = 0;
|
|
|
|
sprintf(temp_buf+strlen(temp_buf), "%d", pcisd->wc_data[WC_DATA_INDEX]);
|
|
for (j = WC_DATA_INDEX + 1; j < WC_DATA_MAX; j++)
|
|
sprintf(temp_buf+strlen(temp_buf), " %d", pcisd->wc_data[j]);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", temp_buf);
|
|
}
|
|
break;
|
|
case CISD_WC_DATA_JSON:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
char temp_buf[1024] = {0,};
|
|
int j = 0;
|
|
|
|
sprintf(temp_buf+strlen(temp_buf), "\"%s\":\"%d\"",
|
|
cisd_wc_data_str[WC_DATA_INDEX+1], pcisd->wc_data[WC_DATA_INDEX+1]);
|
|
for (j = WC_DATA_INDEX + 2; j < WC_DATA_MAX; j++)
|
|
sprintf(temp_buf+strlen(temp_buf), ",\"%s\":\"%d\"",
|
|
cisd_wc_data_str[j], pcisd->wc_data[j]);
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", temp_buf);
|
|
}
|
|
break;
|
|
#endif
|
|
case SAFETY_TIMER_SET:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->safety_timer_set);
|
|
break;
|
|
case BATT_SWELLING_CONTROL:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->skip_swelling);
|
|
break;
|
|
case SAFETY_TIMER_INFO:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%ld\n",
|
|
battery->cal_safety_time);
|
|
break;
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
case BATT_TEMP_TEST:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d %d %d %d\n",
|
|
battery->temperature_test_battery,
|
|
battery->temperature_test_usb,
|
|
battery->temperature_test_wpc,
|
|
battery->temperature_test_chg);
|
|
break;
|
|
#endif
|
|
case BATT_CURRENT_EVENT:
|
|
i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
|
|
battery->current_event);
|
|
break;
|
|
case FACTORY_MODE_RELIEVE:
|
|
break;
|
|
case FACTORY_MODE_BYPASS:
|
|
break;
|
|
case NORMAL_MODE_BYPASS:
|
|
break;
|
|
case FACTORY_VOLTAGE_REGULATION:
|
|
break;
|
|
case FACTORY_MODE_DISABLE:
|
|
break;
|
|
default:
|
|
i = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
void update_external_temp_table(struct sec_battery_info *battery, int temp[])
|
|
{
|
|
battery->pdata->temp_high_threshold_normal = temp[0];
|
|
battery->pdata->temp_high_recovery_normal = temp[1];
|
|
battery->pdata->temp_low_threshold_normal = temp[2];
|
|
battery->pdata->temp_low_recovery_normal = temp[3];
|
|
battery->pdata->temp_high_threshold_lpm = temp[4];
|
|
battery->pdata->temp_high_recovery_lpm = temp[5];
|
|
battery->pdata->temp_low_threshold_lpm = temp[6];
|
|
battery->pdata->temp_low_recovery_lpm = temp[7];
|
|
|
|
}
|
|
|
|
ssize_t sec_bat_store_attrs(
|
|
struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
const ptrdiff_t offset = attr - sec_battery_attrs;
|
|
int ret = -EINVAL;
|
|
int x = 0;
|
|
int t[12];
|
|
int i = 0;
|
|
union power_supply_propval value = {0, };
|
|
|
|
switch (offset) {
|
|
case BATT_RESET_SOC:
|
|
/* Do NOT reset fuel gauge in charging mode */
|
|
if ((battery->cable_type == SEC_BATTERY_CABLE_NONE) ||
|
|
battery->is_jig_on) {
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_BATT_RESET_SOC, 0);
|
|
|
|
value.intval =
|
|
SEC_FUELGAUGE_CAPACITY_TYPE_RESET;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
dev_info(battery->dev,"do reset SOC\n");
|
|
/* update battery info */
|
|
sec_bat_get_battery_info(battery);
|
|
}
|
|
ret = count;
|
|
break;
|
|
case BATT_READ_RAW_SOC:
|
|
break;
|
|
case BATT_READ_ADJ_SOC:
|
|
break;
|
|
case BATT_TYPE:
|
|
strncpy(battery->batt_type, buf, sizeof(battery->batt_type) - 1);
|
|
battery->batt_type[sizeof(battery->batt_type)-1] = '\0';
|
|
ret = count;
|
|
break;
|
|
case BATT_VFOCV:
|
|
break;
|
|
case BATT_VOL_ADC:
|
|
break;
|
|
case BATT_VOL_ADC_CAL:
|
|
break;
|
|
case BATT_VOL_AVER:
|
|
break;
|
|
case BATT_VOL_ADC_AVER:
|
|
break;
|
|
case BATT_CURRENT_UA_NOW:
|
|
break;
|
|
case BATT_CURRENT_UA_AVG:
|
|
break;
|
|
case BATT_FILTER_CFG:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_FILTER_CFG, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_TEMP:
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT) || defined(CONFIG_SEC_FACTORY)
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
dev_info(battery->dev,
|
|
"%s: cooldown mode %s\n", __func__, (x ? "enable" : "disable"));
|
|
if (x == 0)
|
|
battery->cooldown_mode = false;
|
|
else
|
|
battery->cooldown_mode = true;
|
|
ret = count;
|
|
}
|
|
#endif
|
|
break;
|
|
case BATT_TEMP_ADC:
|
|
break;
|
|
case BATT_TEMP_AVER:
|
|
break;
|
|
case BATT_TEMP_ADC_AVER:
|
|
break;
|
|
case USB_TEMP:
|
|
break;
|
|
case USB_TEMP_ADC:
|
|
break;
|
|
case CHG_TEMP:
|
|
break;
|
|
case CHG_TEMP_ADC:
|
|
break;
|
|
case SLAVE_CHG_TEMP:
|
|
break;
|
|
case SLAVE_CHG_TEMP_ADC:
|
|
break;
|
|
case BATT_VF_ADC:
|
|
break;
|
|
case BATT_SLATE_MODE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x == battery->slate_mode) {
|
|
dev_info(battery->dev,
|
|
"%s: skip same slate mode: %d\n", __func__, x);
|
|
return count;
|
|
} else if (x == 1) {
|
|
battery->slate_mode = true;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SLATE, SEC_BAT_CURRENT_EVENT_SLATE);
|
|
dev_info(battery->dev,
|
|
"%s: enable slate mode : %d\n", __func__, x);
|
|
} else if (x == 0) {
|
|
battery->slate_mode = false;
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SLATE);
|
|
dev_info(battery->dev,
|
|
"%s: disable slate mode : %d\n", __func__, x);
|
|
} else {
|
|
dev_info(battery->dev,
|
|
"%s: SLATE MODE unknown command\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_LP_CHARGING:
|
|
break;
|
|
case SIOP_ACTIVATED:
|
|
break;
|
|
case SIOP_LEVEL:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
dev_info(battery->dev,
|
|
"%s: siop level: %d\n", __func__, x);
|
|
|
|
battery->wc_heating_start_time = 0;
|
|
if (x == battery->siop_level) {
|
|
dev_info(battery->dev,
|
|
"%s: skip same siop level: %d\n", __func__, x);
|
|
return count;
|
|
} else if (x >= 0 && x <= 100) {
|
|
battery->siop_level = x;
|
|
} else {
|
|
battery->siop_level = 100;
|
|
}
|
|
|
|
if (battery->siop_event == SIOP_EVENT_WPC_CALL_START ||
|
|
battery->siop_event == SIOP_EVENT_WPC_CALL_END)
|
|
return count;
|
|
|
|
if (delayed_work_pending(&battery->siop_event_work))
|
|
return count;
|
|
|
|
cancel_delayed_work(&battery->siop_work);
|
|
wake_lock(&battery->siop_level_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->siop_level_work, 0);
|
|
|
|
ret = count;
|
|
}
|
|
break;
|
|
case SIOP_EVENT:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (battery->pdata->siop_event_check_type & SIOP_EVENT_WPC_CALL) { // To reduce call noise with battery pack
|
|
if (x == SIOP_EVENT_WPC_CALL_START) {
|
|
battery->siop_event |= SIOP_EVENT_WPC_CALL;
|
|
pr_info("%s : WPC Enable & SIOP EVENT CALL START. 0x%x\n",
|
|
__func__, battery->siop_event);
|
|
cancel_delayed_work(&battery->siop_level_work);
|
|
cancel_delayed_work(&battery->siop_work);
|
|
wake_lock(&battery->siop_event_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->siop_event_work, 0);
|
|
} else if (x == SIOP_EVENT_WPC_CALL_END) {
|
|
battery->siop_event &= ~SIOP_EVENT_WPC_CALL;
|
|
pr_info("%s : WPC Enable & SIOP EVENT CALL END. 0x%x\n",
|
|
__func__, battery->siop_event);
|
|
cancel_delayed_work(&battery->siop_level_work);
|
|
cancel_delayed_work(&battery->siop_work);
|
|
wake_lock(&battery->siop_event_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->siop_event_work,
|
|
msecs_to_jiffies(5000));
|
|
} else {
|
|
battery->siop_event &= ~SIOP_EVENT_WPC_CALL;
|
|
pr_info("%s : WPC Disable & SIOP EVENT 0x%x\n", __func__, battery->siop_event);
|
|
}
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_CHARGING_SOURCE:
|
|
break;
|
|
case FG_REG_DUMP:
|
|
break;
|
|
case FG_RESET_CAP:
|
|
break;
|
|
case FG_CAPACITY:
|
|
break;
|
|
case FG_ASOC:
|
|
break;
|
|
case AUTH:
|
|
break;
|
|
case CHG_CURRENT_ADC:
|
|
break;
|
|
case WC_ADC:
|
|
break;
|
|
case WC_STATUS:
|
|
break;
|
|
case WC_ENABLE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x == 0) {
|
|
battery->wc_enable = false;
|
|
battery->wc_enable_cnt = 0;
|
|
} else if (x == 1) {
|
|
battery->wc_enable = true;
|
|
battery->wc_enable_cnt = 0;
|
|
} else {
|
|
dev_info(battery->dev,
|
|
"%s: WPC ENABLE unknown command\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case WC_CONTROL:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (battery->pdata->wpc_en) {
|
|
if (x == 0) {
|
|
battery->wc_enable = false;
|
|
battery->wc_enable_cnt = 0;
|
|
gpio_direction_output(battery->pdata->wpc_en, 1);
|
|
pr_info("%s: WC CONTROL: Disable", __func__);
|
|
} else if (x == 1) {
|
|
battery->wc_enable = true;
|
|
battery->wc_enable_cnt = 0;
|
|
gpio_direction_output(battery->pdata->wpc_en, 0);
|
|
pr_info("%s: WC CONTROL: Enable", __func__);
|
|
} else {
|
|
dev_info(battery->dev,
|
|
"%s: WC CONTROL unknown command\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case WC_CONTROL_CNT:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
battery->wc_enable_cnt_value = x;
|
|
ret = count;
|
|
}
|
|
break;
|
|
case LED_COVER:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
pr_info("%s: MFC, LED_COVER(%d)\n", __func__, x);
|
|
battery->led_cover = x;
|
|
value.intval = battery->led_cover;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_FILTER_CFG, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case HV_CHARGER_STATUS:
|
|
break;
|
|
case HV_WC_CHARGER_STATUS:
|
|
break;
|
|
case HV_CHARGER_SET:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
dev_info(battery->dev,
|
|
"%s: HV_CHARGER_SET(%d)\n", __func__, x);
|
|
if (x == 1) {
|
|
battery->wire_status = SEC_BATTERY_CABLE_9V_TA;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
} else {
|
|
battery->wire_status = SEC_BATTERY_CABLE_NONE;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case FACTORY_MODE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
battery->factory_mode = x ? true : false;
|
|
ret = count;
|
|
}
|
|
break;
|
|
case STORE_MODE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
if (x) {
|
|
battery->store_mode = true;
|
|
wake_lock(&battery->parse_mode_dt_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->parse_mode_dt_work, 0);
|
|
}
|
|
#endif
|
|
ret = count;
|
|
}
|
|
break;
|
|
case UPDATE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
/* update battery info */
|
|
sec_bat_get_battery_info(battery);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case TEST_MODE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
battery->test_mode = x;
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->monitor_work, 0);
|
|
ret = count;
|
|
}
|
|
break;
|
|
|
|
case BATT_EVENT_CALL:
|
|
case BATT_EVENT_2G_CALL:
|
|
case BATT_EVENT_TALK_GSM:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_3G_CALL:
|
|
case BATT_EVENT_TALK_WCDMA:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_MUSIC:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_VIDEO:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_BROWSER:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_HOTSPOT:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_CAMERA:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_CAMCORDER:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_DATA_CALL:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_WIFI:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_WIBRO:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_LTE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_LCD:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
struct timespec ts;
|
|
get_monotonic_boottime(&ts);
|
|
if (x) {
|
|
battery->lcd_status = true;
|
|
} else {
|
|
battery->lcd_status = false;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_EVENT_GPS:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_TEMP_TABLE:
|
|
if (sscanf(buf, "%10d %10d %10d %10d %10d %10d %10d %10d\n",
|
|
&t[0], &t[1], &t[2], &t[3], &t[4], &t[5], &t[6], &t[7]) == 8) {
|
|
pr_info("%s: (new) %d %d %d %d %d %d %d %d\n",
|
|
__func__, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
|
|
pr_info("%s: (default) %d %d %d %d %d %d %d %d\n",
|
|
__func__,
|
|
battery->pdata->temp_high_threshold_normal,
|
|
battery->pdata->temp_high_recovery_normal,
|
|
battery->pdata->temp_low_threshold_normal,
|
|
battery->pdata->temp_low_recovery_normal,
|
|
battery->pdata->temp_high_threshold_lpm,
|
|
battery->pdata->temp_high_recovery_lpm,
|
|
battery->pdata->temp_low_threshold_lpm,
|
|
battery->pdata->temp_low_recovery_lpm);
|
|
update_external_temp_table(battery, t);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_HIGH_CURRENT_USB:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
battery->is_hc_usb = x ? true : false;
|
|
value.intval = battery->is_hc_usb;
|
|
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_USB_HC, value);
|
|
|
|
pr_info("%s: is_hc_usb (%d)\n", __func__, battery->is_hc_usb);
|
|
ret = count;
|
|
}
|
|
break;
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
case TEST_CHARGE_CURRENT:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x >= 0 && x <= 2000) {
|
|
dev_err(battery->dev,
|
|
"%s: BATT_TEST_CHARGE_CURRENT(%d)\n", __func__, x);
|
|
battery->pdata->charging_current[
|
|
SEC_BATTERY_CABLE_USB].input_current_limit = x;
|
|
battery->pdata->charging_current[
|
|
SEC_BATTERY_CABLE_USB].fast_charging_current = x;
|
|
if (x > 500) {
|
|
battery->eng_not_full_status = true;
|
|
battery->pdata->temp_check_type =
|
|
SEC_BATTERY_TEMP_CHECK_NONE;
|
|
}
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_USB) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_NOW,
|
|
value);
|
|
}
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
#endif
|
|
case SET_STABILITY_TEST:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
dev_err(battery->dev,
|
|
"%s: BATT_STABILITY_TEST(%d)\n", __func__, x);
|
|
if (x) {
|
|
battery->stability_test = true;
|
|
battery->eng_not_full_status = true;
|
|
}
|
|
else {
|
|
battery->stability_test = false;
|
|
battery->eng_not_full_status = false;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_CAPACITY_MAX:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
dev_err(battery->dev,
|
|
"%s: BATT_CAPACITY_MAX(%d), fg_reset(%d)\n", __func__, x, fg_reset);
|
|
if (!fg_reset && !battery->store_mode) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, value);
|
|
|
|
/* update soc */
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
battery->capacity = value.intval;
|
|
} else {
|
|
#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP)
|
|
battery->fg_reset = 1;
|
|
#endif
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_INBAT_VOLTAGE:
|
|
break;
|
|
case BATT_INBAT_VOLTAGE_OCV:
|
|
break;
|
|
case CHECK_SLAVE_CHG:
|
|
break;
|
|
case BATT_INBAT_WIRELESS_CS100:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
pr_info("%s send cs100 command\n", __func__);
|
|
value.intval = POWER_SUPPLY_STATUS_FULL;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_STATUS, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case HMT_TA_CONNECTED:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
#if !defined(CONFIG_CCIC_NOTIFIER)
|
|
dev_info(battery->dev,
|
|
"%s: HMT_TA_CONNECTED(%d)\n", __func__, x);
|
|
if (x) {
|
|
value.intval = false;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
|
|
value);
|
|
dev_info(battery->dev,
|
|
"%s: changed to OTG cable detached\n", __func__);
|
|
|
|
battery->wire_status = SEC_BATTERY_CABLE_HMT_CONNECTED;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
} else {
|
|
value.intval = true;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
|
|
value);
|
|
dev_info(battery->dev,
|
|
"%s: changed to OTG cable attached\n", __func__);
|
|
|
|
battery->wire_status = SEC_BATTERY_CABLE_OTG;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
}
|
|
#endif
|
|
ret = count;
|
|
}
|
|
break;
|
|
case HMT_TA_CHARGE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
dev_info(battery->dev,
|
|
"%s: HMT_TA_CHARGE(%d)\n", __func__, x);
|
|
|
|
/* do not charge off without cable type, since wdt could be expired */
|
|
if (x && (battery->cable_type != SEC_BATTERY_CABLE_NONE)
|
|
&& (battery->cable_type != SEC_BATTERY_CABLE_OTG)) {
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_CHARGE_DISABLE);
|
|
/* No charging when FULL & NONE */
|
|
if (!((battery->status == POWER_SUPPLY_STATUS_FULL) &&
|
|
(battery->charging_mode == SEC_BATTERY_CHARGING_NONE))) {
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
}
|
|
} else if (!x) {
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_CHARGE_DISABLE,
|
|
SEC_BAT_CURRENT_EVENT_CHARGE_DISABLE);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
} else {
|
|
dev_info(battery->dev,
|
|
"%s: Wrong HMT control\n", __func__);
|
|
}
|
|
ret = count;
|
|
#else
|
|
dev_info(battery->dev,
|
|
"%s: HMT_TA_CHARGE(%d)\n", __func__, x);
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
if (value.intval) {
|
|
dev_info(battery->dev,
|
|
"%s: ignore HMT_TA_CHARGE(%d)\n", __func__, x);
|
|
} else {
|
|
if (x) {
|
|
value.intval = false;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
|
|
value);
|
|
dev_info(battery->dev,
|
|
"%s: changed to OTG cable detached\n", __func__);
|
|
battery->wire_status = SEC_BATTERY_CABLE_HMT_CHARGE;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
} else {
|
|
value.intval = false;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
|
|
value);
|
|
dev_info(battery->dev,
|
|
"%s: changed to OTG cable detached\n", __func__);
|
|
battery->wire_status = SEC_BATTERY_CABLE_HMT_CONNECTED;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
}
|
|
}
|
|
ret = count;
|
|
#endif
|
|
}
|
|
break;
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
case FG_CYCLE:
|
|
break;
|
|
case FG_FULL_VOLTAGE:
|
|
break;
|
|
case FG_FULLCAPNOM:
|
|
break;
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST_DETACHABLE)
|
|
case BATT_AFTER_MANUFACTURED:
|
|
#else
|
|
case BATTERY_CYCLE:
|
|
#endif
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
dev_info(battery->dev, "%s: %s(%d)\n", __func__,
|
|
(offset == BATTERY_CYCLE) ?
|
|
"BATTERY_CYCLE" : "BATTERY_CYCLE(W)", x);
|
|
if (x >= 0) {
|
|
int prev_battery_cycle = battery->batt_cycle;
|
|
battery->batt_cycle = x;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_CYCLE] = x;
|
|
#endif
|
|
dev_info(battery->dev,
|
|
"%s: [Long life] prev_battery_cycle = %d, new bat. cycle = %d\n",
|
|
__func__, prev_battery_cycle, battery->batt_cycle);
|
|
if (prev_battery_cycle < 0) {
|
|
dev_info(battery->dev,
|
|
"%s: [Long life] Do sec_bat_aging_check()\n", __func__);
|
|
sec_bat_aging_check(battery);
|
|
}
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
#endif
|
|
case FG_CYCLE_CHECK_VALUE:
|
|
break;
|
|
case BATT_WPC_TEMP:
|
|
case BATT_WPC_TEMP_ADC:
|
|
case BATT_COIL_TEMP:
|
|
case BATT_COIL_TEMP_ADC:
|
|
break;
|
|
#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE)
|
|
case BATT_WIRELESS_FIRMWARE_UPDATE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x == SEC_WIRELESS_RX_SDCARD_MODE) {
|
|
pr_info("%s fw mode is SDCARD\n", __func__);
|
|
sec_bat_fw_update_work(battery, SEC_WIRELESS_RX_SDCARD_MODE);
|
|
} else if (x == SEC_WIRELESS_RX_BUILT_IN_MODE) {
|
|
pr_info("%s fw mode is BUILD IN\n", __func__);
|
|
sec_bat_fw_update_work(battery, SEC_WIRELESS_RX_BUILT_IN_MODE);
|
|
} else if (x == SEC_WIRELESS_TX_ON_MODE) {
|
|
pr_info("%s tx mode is on\n", __func__);
|
|
sec_bat_fw_update_work(battery, SEC_WIRELESS_TX_ON_MODE);
|
|
} else if (x == SEC_WIRELESS_TX_OFF_MODE) {
|
|
pr_info("%s tx mode is off\n", __func__);
|
|
sec_bat_fw_update_work(battery, SEC_WIRELESS_TX_OFF_MODE);
|
|
} else {
|
|
dev_info(battery->dev, "%s: wireless firmware unknown command\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case OTP_FIRMWARE_RESULT:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x == 2) {
|
|
value.intval = x;
|
|
pr_info("%s RX firmware update ready!\n", __func__);
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_MANUFACTURER, value);
|
|
} else {
|
|
dev_info(battery->dev, "%s: firmware unknown command\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case WC_IC_GRADE:
|
|
case OTP_FIRMWARE_VER_BIN:
|
|
case OTP_FIRMWARE_VER:
|
|
case TX_FIRMWARE_RESULT:
|
|
case TX_FIRMWARE_VER:
|
|
break;
|
|
case BATT_TX_STATUS:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x == SEC_TX_OFF) {
|
|
pr_info("%s TX mode is off\n", __func__);
|
|
sec_bat_fw_update_work(battery, SEC_WIRELESS_TX_OFF_MODE);
|
|
} else if (x == SEC_TX_STANDBY) {
|
|
pr_info("%s TX mode is on\n", __func__);
|
|
sec_bat_fw_update_work(battery, SEC_WIRELESS_TX_ON_MODE);
|
|
} else {
|
|
dev_info(battery->dev, "%s: TX firmware unknown command\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
#endif
|
|
case WC_VOUT:
|
|
case WC_VRECT:
|
|
break;
|
|
case BATT_HV_WIRELESS_STATUS:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x == 1 && is_hv_wireless_type(battery->cable_type)) {
|
|
wake_lock(&battery->cable_wake_lock);
|
|
#ifdef CONFIG_SEC_FACTORY
|
|
pr_info("%s change cable type HV WIRELESS -> WIRELESS\n", __func__);
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC;
|
|
battery->cable_type = SEC_BATTERY_CABLE_WIRELESS;
|
|
sec_bat_set_charging_current(battery);
|
|
#endif
|
|
pr_info("%s HV_WIRELESS_STATUS set to 1. Vout set to 5V.\n", __func__);
|
|
value.intval = WIRELESS_VOUT_5V;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
wake_unlock(&battery->cable_wake_lock);
|
|
} else if (x == 3 && is_hv_wireless_type(battery->cable_type)) {
|
|
pr_info("%s HV_WIRELESS_STATUS set to 3. Vout set to 10V.\n", __func__);
|
|
value.intval = WIRELESS_VOUT_10V;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
} else {
|
|
dev_info(battery->dev, "%s: HV_WIRELESS_STATUS unknown command\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_HV_WIRELESS_PAD_CTRL:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
|
|
pr_err("%s: x : %d\n", __func__, x);
|
|
|
|
if (x == 1) {
|
|
#if 0
|
|
ret = sec_set_param(CM_OFFSET, '1');
|
|
#endif
|
|
if (ret < 0) {
|
|
pr_err("%s:sec_set_param failed\n", __func__);
|
|
return ret;
|
|
} else {
|
|
pr_info("%s fan off\n", __func__);
|
|
sleep_mode = true;
|
|
if (is_hv_wireless_type(battery->cable_type)) {
|
|
value.intval = WIRELESS_PAD_FAN_ON;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
msleep(250);
|
|
value.intval = WIRELESS_PAD_FAN_OFF;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
|
|
msleep(250);
|
|
value.intval = battery->pdata->sleep_mode_limit_current;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
battery->input_current = value.intval;
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
}
|
|
}
|
|
} else if (x == 2) {
|
|
#if 0
|
|
ret = sec_set_param(CM_OFFSET, '0');
|
|
#endif
|
|
if (ret < 0) {
|
|
pr_err("%s: sec_set_param failed\n", __func__);
|
|
return ret;
|
|
} else {
|
|
sleep_mode = false;
|
|
pr_info("%s fan on\n", __func__);
|
|
if (is_hv_wireless_type(battery->cable_type)) {
|
|
value.intval = WIRELESS_PAD_FAN_ON;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
|
|
msleep(250);
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
}
|
|
}
|
|
} else if (x == 3) {
|
|
pr_info("%s led off\n", __func__);
|
|
value.intval = WIRELESS_PAD_LED_OFF;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
} else if (x == 4) {
|
|
pr_info("%s led on\n", __func__);
|
|
value.intval = WIRELESS_PAD_LED_ON;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
} else {
|
|
dev_info(battery->dev, "%s: BATT_HV_WIRELESS_PAD_CTRL unknown command\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_TUNE_FLOAT_VOLTAGE:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s float voltage = %d mV",__func__, x);
|
|
|
|
if (x > 4000 && x <= 4400 ) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, value);
|
|
}
|
|
break;
|
|
case BATT_TUNE_INPUT_CHARGE_CURRENT:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s input charge current = %d mA",__func__, x);
|
|
|
|
if (x >= 0 && x <= 4000 ) {
|
|
for (i=0; i < SEC_BATTERY_CABLE_MAX; i++) {
|
|
battery->pdata->charging_current[i].input_current_limit = x;
|
|
}
|
|
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
}
|
|
break;
|
|
case BATT_TUNE_FAST_CHARGE_CURRENT:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s fast charge current = %d mA",__func__, x);
|
|
if (x >= 0 && x <= 4000 ) {
|
|
for (i=0; i < SEC_BATTERY_CABLE_MAX; i++) {
|
|
battery->pdata->charging_current[i].fast_charging_current = x;
|
|
}
|
|
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_AVG, value);
|
|
}
|
|
break;
|
|
case BATT_TUNE_UI_TERM_CURRENT_1ST:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s ui term current = %d mA",__func__, x);
|
|
|
|
if (x > 0 && x < 1000 ) {
|
|
battery->pdata->full_check_current_1st = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_UI_TERM_CURRENT_2ND:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s ui term current = %d mA",__func__, x);
|
|
|
|
if (x > 0 && x < 1000 ) {
|
|
battery->pdata->full_check_current_2nd = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_TEMP_HIGH_NORMAL:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s temp high normal block = %d ",__func__, x);
|
|
if (x < 1000 && x >= -200) {
|
|
battery->pdata->temp_high_threshold_normal = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_TEMP_HIGH_REC_NORMAL:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s temp high normal recover = %d ",__func__, x);
|
|
if (x < 1000 && x >= -200) {
|
|
battery->pdata->temp_high_recovery_normal = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_TEMP_LOW_NORMAL:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s temp low normal block = %d ",__func__, x);
|
|
if (x < 1000 && x >= -200) {
|
|
battery->pdata->temp_low_threshold_normal = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_TEMP_LOW_REC_NORMAL:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s temp low normal recover = %d ",__func__, x);
|
|
if (x < 1000 && x >= -200) {
|
|
battery->pdata->temp_low_recovery_normal = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_CHG_TEMP_HIGH:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s chg_high_temp = %d ",__func__, x);
|
|
if (x < 1000 && x >= -200) {
|
|
battery->pdata->chg_high_temp = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_CHG_TEMP_REC:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s chg_high_temp_recovery = %d ",__func__, x);
|
|
if (x < 1000 && x >= -200) {
|
|
battery->pdata->chg_high_temp_recovery = x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_CHG_LIMIT_CUR:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s chg_charging_limit_current = %d ",__func__, x);
|
|
if (x <3000 && x > 0) {
|
|
battery->pdata->chg_charging_limit_current = x;
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_9V_ERR].input_current_limit= x;
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_9V_UNKNOWN].input_current_limit= x;
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_9V_TA].input_current_limit= x;
|
|
}
|
|
break;
|
|
case BATT_TUNE_COIL_TEMP_HIGH:
|
|
break;
|
|
case BATT_TUNE_COIL_TEMP_REC:
|
|
break;
|
|
case BATT_TUNE_COIL_LIMIT_CUR:
|
|
sscanf(buf, "%10d\n", &x);
|
|
pr_info("%s wpc_charging_limit_current = %d ",__func__, x);
|
|
if (x <3000 && x > 0) {
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_9V_ERR].input_current_limit= x;
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_9V_UNKNOWN].input_current_limit= x;
|
|
battery->pdata->charging_current[SEC_BATTERY_CABLE_9V_TA].input_current_limit= x;
|
|
}
|
|
break;
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
case BATT_UPDATE_DATA:
|
|
if (!battery->data_path && (count * sizeof(char)) < 256) {
|
|
battery->data_path = kzalloc((count * sizeof(char) + 1), GFP_KERNEL);
|
|
if (battery->data_path) {
|
|
sscanf(buf, "%s\n", battery->data_path);
|
|
cancel_delayed_work(&battery->batt_data_work);
|
|
wake_lock(&battery->batt_data_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->batt_data_work, msecs_to_jiffies(100));
|
|
} else {
|
|
pr_info("%s: failed to alloc data_path buffer\n", __func__);
|
|
}
|
|
}
|
|
ret = count;
|
|
break;
|
|
#endif
|
|
case BATT_MISC_EVENT:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
pr_info("%s: PMS sevice hiccup read done : %d ",__func__, x);
|
|
if (!battery->hiccup_status &&
|
|
(battery->misc_event & BATT_MISC_EVENT_HICCUP_TYPE)) {
|
|
sec_bat_set_misc_event(battery,
|
|
BATT_MISC_EVENT_HICCUP_TYPE, 1);
|
|
}
|
|
}
|
|
ret = count;
|
|
break;
|
|
case BATT_EXT_DEV_CHG:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
pr_info("%s: Connect Ext Device : %d ",__func__, x);
|
|
|
|
switch (x) {
|
|
case EXT_DEV_NONE:
|
|
battery->wire_status = SEC_BATTERY_CABLE_NONE;
|
|
value.intval = 0;
|
|
break;
|
|
case EXT_DEV_GAMEPAD_CHG:
|
|
battery->wire_status = SEC_BATTERY_CABLE_TA;
|
|
value.intval = 0;
|
|
break;
|
|
case EXT_DEV_GAMEPAD_OTG:
|
|
battery->wire_status = SEC_BATTERY_CABLE_OTG;
|
|
value.intval = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
|
|
value);
|
|
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_WDT_CONTROL:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
pr_info("%s: Charger WDT Set : %d\n", __func__, x);
|
|
battery->wdt_kick_disable = x;
|
|
}
|
|
ret = count;
|
|
break;
|
|
case MODE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_MULTI_CHARGER_MODE, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case CHECK_PS_READY:
|
|
case BATT_CHIP_ID:
|
|
break;
|
|
case CISD_FULLCAPREP_MAX:
|
|
break;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
case CISD_DATA:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
int temp_data[CISD_DATA_MAX_PER_DAY] = {0,};
|
|
|
|
sscanf(buf, "%10d\n", &temp_data[0]);
|
|
|
|
if (temp_data[CISD_DATA_RESET_ALG] > 0) {
|
|
if (sscanf(buf, "%10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d, %10d\n",
|
|
&temp_data[0], &temp_data[1], &temp_data[2],
|
|
&temp_data[3], &temp_data[4], &temp_data[5],
|
|
&temp_data[6], &temp_data[7], &temp_data[8],
|
|
&temp_data[9], &temp_data[10], &temp_data[11],
|
|
&temp_data[12], &temp_data[13], &temp_data[14],
|
|
&temp_data[15], &temp_data[16], &temp_data[17],
|
|
&temp_data[18], &temp_data[19], &temp_data[20],
|
|
&temp_data[21], &temp_data[22], &temp_data[23],
|
|
&temp_data[24], &temp_data[25], &temp_data[26],
|
|
&temp_data[27], &temp_data[28], &temp_data[29],
|
|
&temp_data[30], &temp_data[31], &temp_data[32],
|
|
&temp_data[33], &temp_data[34], &temp_data[35],
|
|
&temp_data[36], &temp_data[37], &temp_data[38],
|
|
&temp_data[39], &temp_data[40], &temp_data[41],
|
|
&temp_data[42], &temp_data[43], &temp_data[44],
|
|
&temp_data[45], &temp_data[46], &temp_data[47],
|
|
&temp_data[48], &temp_data[49], &temp_data[50],
|
|
&temp_data[51], &temp_data[52], &temp_data[53],
|
|
&temp_data[54], &temp_data[55], &temp_data[56],
|
|
&temp_data[57], &temp_data[58], &temp_data[59],
|
|
&temp_data[60], &temp_data[61], &temp_data[62],
|
|
&temp_data[63], &temp_data[64], &temp_data[65],
|
|
&temp_data[66], &temp_data[67], &temp_data[68],
|
|
&temp_data[69], &temp_data[70], &temp_data[71],
|
|
&temp_data[72], &temp_data[73], &temp_data[74],
|
|
&temp_data[75], &temp_data[76]) <= CISD_DATA_MAX_PER_DAY) {
|
|
for (i = 0; i < CISD_DATA_MAX_PER_DAY; i++)
|
|
pcisd->data[i] = 0;
|
|
pcisd->data[CISD_DATA_ALG_INDEX] = battery->pdata->cisd_alg_index;
|
|
pcisd->data[CISD_DATA_FULL_COUNT] = temp_data[0];
|
|
pcisd->data[CISD_DATA_CAP_MAX] = temp_data[1];
|
|
pcisd->data[CISD_DATA_CAP_MIN] = temp_data[2];
|
|
pcisd->data[CISD_DATA_VALERT_COUNT] = temp_data[16];
|
|
pcisd->data[CISD_DATA_CYCLE] = temp_data[17];
|
|
pcisd->data[CISD_DATA_WIRE_COUNT] = temp_data[18];
|
|
pcisd->data[CISD_DATA_WIRELESS_COUNT] = temp_data[19];
|
|
pcisd->data[CISD_DATA_HIGH_TEMP_SWELLING] = temp_data[20];
|
|
pcisd->data[CISD_DATA_LOW_TEMP_SWELLING] = temp_data[21];
|
|
pcisd->data[CISD_DATA_SWELLING_CHARGING_COUNT] = temp_data[22];
|
|
pcisd->data[CISD_DATA_AICL_COUNT] = temp_data[26];
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MAX] = temp_data[27];
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MIN] = temp_data[28];
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MAX] = temp_data[29];
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MIN] = temp_data[30];
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MAX] = temp_data[31];
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MIN] = temp_data[32];
|
|
pcisd->data[CISD_DATA_UNSAFETY_VOLTAGE] = temp_data[33];
|
|
pcisd->data[CISD_DATA_UNSAFETY_TEMPERATURE] = temp_data[34];
|
|
pcisd->data[CISD_DATA_SAFETY_TIMER] = temp_data[35];
|
|
pcisd->data[CISD_DATA_VSYS_OVP] = temp_data[36];
|
|
pcisd->data[CISD_DATA_VBAT_OVP] = temp_data[37];
|
|
pcisd->data[CISD_DATA_AFC_FAIL] = temp_data[39];
|
|
pcisd->data[CISD_DATA_WATER_DETECT] = temp_data[38];
|
|
}
|
|
} else {
|
|
const char *p = buf;
|
|
|
|
pr_info("%s: %s\n", __func__, buf);
|
|
for (i = CISD_DATA_RESET_ALG; i < CISD_DATA_MAX_PER_DAY; i++) {
|
|
if (sscanf(p, "%10d%n", &pcisd->data[i], &x) > 0)
|
|
p += (size_t)x;
|
|
else {
|
|
pr_info("%s: NO DATA (cisd_data)\n", __func__);
|
|
temp_data[CISD_DATA_RESET_ALG] = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pr_info("%s: %s cisd data\n", __func__,
|
|
((temp_data[CISD_DATA_RESET_ALG] < 0 || battery->fg_reset) ? "init" : "update"));
|
|
|
|
if (temp_data[CISD_DATA_RESET_ALG] < 0 || battery->fg_reset) {
|
|
/* initialize data */
|
|
for (i = CISD_DATA_RESET_ALG; i < CISD_DATA_MAX_PER_DAY; i++)
|
|
pcisd->data[i] = 0;
|
|
for (i = WC_DATA_INDEX; i < WC_DATA_MAX; i++)
|
|
pcisd->wc_data[i] = 0;
|
|
|
|
battery->fg_reset = 0;
|
|
|
|
pcisd->data[CISD_DATA_ALG_INDEX] = battery->pdata->cisd_alg_index;
|
|
|
|
pcisd->data[CISD_DATA_FULL_COUNT] = 1;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CAP_MIN] = 0xFFFF;
|
|
|
|
pcisd->data[CISD_DATA_FULL_COUNT_PER_DAY] = 1;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MIN_PER_DAY] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MIN] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MIN_PER_DAY] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CAP_MIN_PER_DAY] = 0xFFFF;
|
|
}
|
|
}
|
|
ret = count;
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
}
|
|
break;
|
|
case CISD_DATA_JSON:
|
|
{
|
|
char tc;
|
|
struct cisd *pcisd = &battery->cisd;
|
|
|
|
if (sscanf(buf, "%1c\n", &tc) == 1) {
|
|
if (tc == 'c') {
|
|
for (i = 0; i < CISD_DATA_MAX; i++)
|
|
pcisd->data[i] = 0;
|
|
|
|
pcisd->data[CISD_DATA_FULL_COUNT] = 1;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CAP_MIN] = 0xFFFF;
|
|
|
|
pcisd->data[CISD_DATA_FULL_COUNT_PER_DAY] = 1;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_BATT_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_WPC_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_USB_TEMP_MIN_PER_DAY] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MAX] = -300;
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MIN] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MIN] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MAX_PER_DAY] = -300;
|
|
pcisd->data[CISD_DATA_CHG_BATT_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_CHG_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_WPC_TEMP_MIN_PER_DAY] = 1000;
|
|
pcisd->data[CISD_DATA_CHG_USB_TEMP_MIN_PER_DAY] = 1000;
|
|
|
|
pcisd->data[CISD_DATA_CAP_MIN_PER_DAY] = 0xFFFF;
|
|
|
|
}
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case CISD_DATA_D_JSON:
|
|
break;
|
|
case CISD_WIRE_COUNT:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
struct cisd *pcisd = &battery->cisd;
|
|
pr_info("%s: Wire Count : %d\n", __func__, x);
|
|
pcisd->data[CISD_DATA_WIRE_COUNT] = x;
|
|
pcisd->data[CISD_DATA_WIRE_COUNT_PER_DAY]++;
|
|
}
|
|
ret = count;
|
|
break;
|
|
case CISD_WC_DATA:
|
|
{
|
|
struct cisd *pcisd = &battery->cisd;
|
|
const char *p = buf;
|
|
|
|
pr_info("%s: %s\n", __func__, buf);
|
|
for (i = WC_DATA_INDEX; i < WC_DATA_MAX; i++) {
|
|
sscanf(p, "%10d%n", &pcisd->wc_data[i], &x);
|
|
p += x;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case CISD_WC_DATA_JSON:
|
|
break;
|
|
#endif
|
|
case SAFETY_TIMER_SET:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x) {
|
|
battery->safety_timer_set = true;
|
|
} else {
|
|
battery->safety_timer_set = false;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case BATT_SWELLING_CONTROL:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (x) {
|
|
pr_info("%s : 15TEST START!! SWELLING MODE DISABLE\n", __func__);
|
|
battery->skip_swelling = true;
|
|
} else {
|
|
pr_info("%s : 15TEST END!! SWELLING MODE END\n", __func__);
|
|
battery->skip_swelling = false;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
case SAFETY_TIMER_INFO:
|
|
break;
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
case BATT_TEMP_TEST:
|
|
{
|
|
char tc;
|
|
if (sscanf(buf, "%c %10d\n", &tc, &x) == 2) {
|
|
pr_info("%s : temperature t: %c, temp: %d\n", __func__, tc, x);
|
|
if (tc == 'u') {
|
|
battery->temperature_test_usb = x;
|
|
} else if (tc == 'w') {
|
|
battery->temperature_test_wpc = x;
|
|
} else if (tc == 'b') {
|
|
battery->temperature_test_battery = x;
|
|
} else if (tc == 'c') {
|
|
battery->temperature_test_chg = x;
|
|
}
|
|
ret = count;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
case BATT_CURRENT_EVENT:
|
|
break;
|
|
case FACTORY_MODE_RELIEVE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case FACTORY_MODE_BYPASS:
|
|
pr_info("%s: factory mode bypass\n", __func__);
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_AUTHENTIC, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case NORMAL_MODE_BYPASS:
|
|
pr_info("%s: normal mode bypass for current measure\n", __func__);
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
if (battery->pdata->detect_moisture && x) {
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_DISCHARGING);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
}
|
|
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_CURRENT_MEASURE, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
case FACTORY_VOLTAGE_REGULATION:
|
|
{
|
|
sscanf(buf, "%10d\n", &x);
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_FACTORY_VOLTAGE_REGULATION, value);
|
|
|
|
value.intval =
|
|
SEC_FUELGAUGE_CAPACITY_TYPE_RESET;
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
dev_info(battery->dev,"do reset SOC\n");
|
|
/* update battery info */
|
|
sec_bat_get_battery_info(battery);
|
|
}
|
|
ret = count;
|
|
break;
|
|
case FACTORY_MODE_DISABLE:
|
|
if (sscanf(buf, "%10d\n", &x) == 1) {
|
|
value.intval = x;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_DISABLE_FACTORY_MODE, value);
|
|
ret = count;
|
|
}
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(CONFIG_ENABLE_USB_SUSPEND_STATE)
|
|
static void sec_bat_do_suspend_resume(struct sec_battery_info * battery, int mode) {
|
|
/* 1: suspend mode, 100: unconfigured */
|
|
pr_info("%s: mode: %d, battery->usb_suspend_mode: %d, cable_type: %s\n",
|
|
__func__, mode, battery->usb_suspend_mode, sec_cable_type[battery->cable_type]);
|
|
if (mode == USB_CURRENT_UNCONFIGURED)
|
|
mode = 0;
|
|
|
|
if ((battery->cable_type == SEC_BATTERY_CABLE_USB) && !lpcharge) {
|
|
if (battery->usb_suspend_mode != mode) {
|
|
if (mode == 1) {
|
|
pr_info("%s: usb suspend\n", __func__);
|
|
battery->usb_suspend_mode = true;
|
|
} else {
|
|
pr_info("%s: usb unconfigured\n", __func__);
|
|
battery->usb_suspend_mode = false;
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING);
|
|
}
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int sec_bat_create_attrs(struct device *dev)
|
|
{
|
|
unsigned long i = 0;
|
|
int rc = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sec_battery_attrs); i++) {
|
|
rc = device_create_file(dev, &sec_battery_attrs[i]);
|
|
if (rc)
|
|
goto create_attrs_failed;
|
|
}
|
|
goto create_attrs_succeed;
|
|
|
|
create_attrs_failed:
|
|
while (i--)
|
|
device_remove_file(dev, &sec_battery_attrs[i]);
|
|
create_attrs_succeed:
|
|
return rc;
|
|
}
|
|
|
|
static int sec_bat_set_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
const union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
int current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
int full_check_type = SEC_BATTERY_FULLCHARGED_NONE;
|
|
union power_supply_propval value = {0, };
|
|
enum power_supply_ext_property ext_psp = psp;
|
|
|
|
dev_dbg(battery->dev,
|
|
"%s: (%d,%d)\n", __func__, psp, val->intval);
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
if (battery->charging_mode == SEC_BATTERY_CHARGING_1ST)
|
|
full_check_type = battery->pdata->full_check_type;
|
|
else
|
|
full_check_type = battery->pdata->full_check_type_2nd;
|
|
if ((full_check_type == SEC_BATTERY_FULLCHARGED_CHGINT) &&
|
|
(val->intval == POWER_SUPPLY_STATUS_FULL))
|
|
sec_bat_do_fullcharged(battery);
|
|
sec_bat_set_charging_status(battery, val->intval);
|
|
break;
|
|
case POWER_SUPPLY_PROP_HEALTH:
|
|
sec_bat_ovp_uvlo_result(battery, val->intval);
|
|
break;
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
current_cable_type = val->intval;
|
|
#if !defined(CONFIG_CCIC_NOTIFIER)
|
|
if ((battery->muic_cable_type != ATTACHED_DEV_SMARTDOCK_TA_MUIC) &&
|
|
((current_cable_type == SEC_BATTERY_CABLE_SMART_OTG) ||
|
|
(current_cable_type == SEC_BATTERY_CABLE_SMART_NOTG)))
|
|
break;
|
|
#endif
|
|
|
|
if (current_cable_type < 0) {
|
|
dev_info(battery->dev,
|
|
"%s: ignore event(%d)\n",
|
|
__func__, current_cable_type);
|
|
} else if (current_cable_type == SEC_BATTERY_CABLE_OTG) {
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->is_recharging = false;
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
battery->cable_type = current_cable_type;
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->monitor_work, 0);
|
|
break;
|
|
} else {
|
|
battery->wire_status = current_cable_type;
|
|
if ((battery->wire_status == SEC_BATTERY_CABLE_NONE) &&
|
|
(battery->wc_status != SEC_WIRELESS_PAD_NONE) )
|
|
current_cable_type = SEC_BATTERY_CABLE_WIRELESS;
|
|
}
|
|
dev_info(battery->dev,
|
|
"%s: current_cable(%d), wc_status(%d), wire_status(%d)\n",
|
|
__func__, current_cable_type, battery->wc_status,
|
|
battery->wire_status);
|
|
|
|
/* cable is attached or detached
|
|
* if current_cable_type is minus value,
|
|
* check cable by sec_bat_get_cable_type()
|
|
* although SEC_BATTERY_CABLE_SOURCE_EXTERNAL is set
|
|
* (0 is SEC_BATTERY_CABLE_UNKNOWN)
|
|
*/
|
|
if ((current_cable_type >= 0) &&
|
|
(current_cable_type < SEC_BATTERY_CABLE_MAX) &&
|
|
(battery->pdata->cable_source_type &
|
|
SEC_BATTERY_CABLE_SOURCE_EXTERNAL)) {
|
|
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work,0);
|
|
} else {
|
|
if (sec_bat_get_cable_type(battery,
|
|
battery->pdata->cable_source_type)) {
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work,0);
|
|
}
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_CAPACITY:
|
|
battery->capacity = val->intval;
|
|
power_supply_changed(battery->psy_bat);
|
|
break;
|
|
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
|
/* If JIG is attached, the voltage is set as 1079 */
|
|
pr_info("%s : set to the battery history : (%d)\n",__func__, val->intval);
|
|
if (val->intval == 1079) {
|
|
battery->voltage_now = 1079;
|
|
battery->voltage_avg = 1079;
|
|
power_supply_changed(battery->psy_bat);
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
break;
|
|
case POWER_SUPPLY_PROP_PRESENT:
|
|
battery->present = val->intval;
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->monitor_work, 0);
|
|
break;
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
|
break;
|
|
#endif
|
|
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION:
|
|
case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL:
|
|
value.intval = val->intval;
|
|
pr_info("%s: CHGIN-OTG %s\n", __func__, value.intval > 0 ? "on" : "off");
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL:
|
|
value.intval = val->intval;
|
|
pr_info("%s: WCIN-UNO %s\n", __func__, value.intval > 0 ? "on" : "off");
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value);
|
|
break;
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
case POWER_SUPPLY_PROP_POWER_DESIGN:
|
|
sec_bat_parse_dt(battery->dev, battery);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
|
|
pr_info("%s: Valert was occured! run monitor work for updating cisd data!\n", __func__);
|
|
battery->cisd.data[CISD_DATA_VALERT_COUNT]++;
|
|
battery->cisd.data[CISD_DATA_VALERT_COUNT_PER_DAY]++;
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work_on(0, battery->monitor_wqueue,
|
|
&battery->monitor_work, 0);
|
|
break;
|
|
#endif
|
|
#if !defined(CONFIG_ENG_BATTERY_CONCEPT) && !defined(CONFIG_SEC_FACTORY)
|
|
case POWER_SUPPLY_PROP_SCOPE:
|
|
battery->block_water_event = val->intval;
|
|
break;
|
|
#endif
|
|
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
|
value.intval = val->intval;
|
|
psy_do_property(battery->pdata->charger_name, set, psp, value);
|
|
break;
|
|
case POWER_SUPPLY_PROP_MAX ... POWER_SUPPLY_EXT_PROP_MAX:
|
|
switch (ext_psp) {
|
|
case POWER_SUPPLY_EXT_PROP_AICL_CURRENT:
|
|
battery->aicl_current = val->intval;
|
|
battery->max_charge_power = battery->charge_power = battery->input_voltage * val->intval;
|
|
pr_info("%s: aicl : %dmA, %dmW\n", __func__,
|
|
battery->aicl_current, battery->charge_power);
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_AICL_COUNT]++;
|
|
battery->cisd.data[CISD_DATA_AICL_COUNT_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_MULTI_CHARGING)
|
|
value.intval = val->intval;
|
|
psy_do_property(battery->pdata->charger_name, set, psp, value);
|
|
#endif
|
|
break;
|
|
case POWER_SUPPLY_EXT_PROP_SYSOVLO:
|
|
if (battery->status != POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
pr_info("%s: Vsys is ovlo !!\n", __func__);
|
|
battery->is_sysovlo = true;
|
|
battery->is_recharging = false;
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->health = POWER_SUPPLY_HEALTH_VSYS_OVP;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_VSYS_OVP, SEC_BAT_CURRENT_EVENT_VSYS_OVP);
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_VSYS_OVP]++;
|
|
battery->cisd.data[CISD_DATA_VSYS_OVP_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_SEC_ABC)
|
|
sec_abc_send_event("MODULE=battery@ERROR=vsys_ovp");
|
|
#endif
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->monitor_work, 0);
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_EXT_PROP_VBAT_OVP:
|
|
if (battery->status != POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
pr_info("%s: Vbat is ovlo !!\n", __func__);
|
|
battery->is_vbatovlo = true;
|
|
battery->is_recharging = false;
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->health = POWER_SUPPLY_HEALTH_VBAT_OVP;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_VBAT_OVP, SEC_BAT_CURRENT_EVENT_VBAT_OVP);
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->monitor_work, 0);
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_EXT_PROP_USB_CONFIGURE:
|
|
pr_info("%s: usb configured %d\n", __func__, val->intval);
|
|
if (val->intval == USB_CURRENT_UNCONFIGURED) {
|
|
#if defined (CONFIG_ENABLE_USB_SUSPEND_STATE)
|
|
sec_bat_do_suspend_resume(battery, USB_CURRENT_UNCONFIGURED);
|
|
#endif
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_USB_100MA,
|
|
(SEC_BAT_CURRENT_EVENT_USB_100MA | SEC_BAT_CURRENT_EVENT_USB_SUPER));
|
|
} else if (val->intval == battery->pdata->default_usb_output_current) {
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_TIMEOUT_OPEN_TYPE, 1);
|
|
sec_bat_set_current_event(battery, 0,
|
|
(SEC_BAT_CURRENT_EVENT_USB_100MA | SEC_BAT_CURRENT_EVENT_USB_SUPER));
|
|
sec_bat_change_default_current(battery, SEC_BATTERY_CABLE_USB,
|
|
battery->pdata->default_usb_output_current,
|
|
battery->pdata->default_usb_output_current);
|
|
} else if (val->intval == USB_CURRENT_SUPER_SPEED) {
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_TIMEOUT_OPEN_TYPE, 1);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_USB_SUPER,
|
|
(SEC_BAT_CURRENT_EVENT_USB_100MA | SEC_BAT_CURRENT_EVENT_USB_SUPER));
|
|
sec_bat_change_default_current(battery, SEC_BATTERY_CABLE_USB,
|
|
USB_CURRENT_SUPER_SPEED, USB_CURRENT_SUPER_SPEED);
|
|
} else {
|
|
#if defined (CONFIG_ENABLE_USB_SUSPEND_STATE)
|
|
if (val->intval == USB_CURRENT_SUSPENDED)
|
|
sec_bat_do_suspend_resume(battery, USB_CURRENT_SUSPENDED);
|
|
#endif
|
|
}
|
|
sec_bat_set_charging_current(battery);
|
|
break;
|
|
case POWER_SUPPLY_EXT_PROP_HV_DISABLE:
|
|
pr_info("HV wired charging mode is %s\n", (val->intval == CH_MODE_AFC_DISABLE_VAL ? "Disabled" : "Enabled"));
|
|
sec_bat_set_current_event(battery, (val->intval == CH_MODE_AFC_DISABLE_VAL ?
|
|
SEC_BAT_CURRENT_EVENT_HV_DISABLE : 0), SEC_BAT_CURRENT_EVENT_HV_DISABLE);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sec_bat_get_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
union power_supply_propval value = {0, };
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
if ((battery->health == POWER_SUPPLY_HEALTH_OVERVOLTAGE) ||
|
|
(battery->health == POWER_SUPPLY_HEALTH_UNDERVOLTAGE)) {
|
|
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
|
} else {
|
|
if ((battery->pdata->cable_check_type &
|
|
SEC_BATTERY_CABLE_CHECK_NOUSBCHARGE) &&
|
|
!lpcharge) {
|
|
switch (battery->cable_type) {
|
|
case SEC_BATTERY_CABLE_USB:
|
|
case SEC_BATTERY_CABLE_USB_CDP:
|
|
val->intval =
|
|
POWER_SUPPLY_STATUS_DISCHARGING;
|
|
return 0;
|
|
}
|
|
}
|
|
#if defined(CONFIG_STORE_MODE)
|
|
if (battery->store_mode && !lpcharge &&
|
|
battery->cable_type != SEC_BATTERY_CABLE_NONE &&
|
|
battery->cable_type != SEC_BATTERY_CABLE_OTG &&
|
|
battery->status == POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
|
} else
|
|
#endif
|
|
val->intval = battery->status;
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE) {
|
|
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
|
} else if (battery->current_event & SEC_BAT_CURRENT_EVENT_AFC ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_PREPARE_TA ||
|
|
battery->cable_type == SEC_BATTERY_CABLE_HV_TA_CHG_LIMIT ||
|
|
is_hv_wire_type(battery->cable_type) ||
|
|
is_pd_wire_type(battery->cable_type) ||
|
|
delayed_work_pending(&battery->slowcharging_work)) {
|
|
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
|
|
} else {
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_CHARGE_TYPE, value);
|
|
if (value.intval == SEC_BATTERY_CABLE_UNKNOWN)
|
|
/* if error in CHARGE_TYPE of charger
|
|
* set CHARGE_TYPE as NONE
|
|
*/
|
|
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
|
else
|
|
val->intval = value.intval;
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_HEALTH:
|
|
if (battery->health >= POWER_SUPPLY_HEALTH_MAX)
|
|
val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
|
|
else
|
|
val->intval = battery->health;
|
|
break;
|
|
case POWER_SUPPLY_PROP_PRESENT:
|
|
val->intval = battery->present;
|
|
break;
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
if (is_hv_wireless_type(battery->cable_type) ||
|
|
(battery->cable_type == SEC_BATTERY_CABLE_PREPARE_WIRELESS_HV)) {
|
|
if (sec_bat_hv_wc_normal_mode_check(battery))
|
|
val->intval = SEC_BATTERY_CABLE_WIRELESS;
|
|
else
|
|
val->intval = SEC_BATTERY_CABLE_HV_WIRELESS_ETX;
|
|
}
|
|
else if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK)
|
|
val->intval = SEC_BATTERY_CABLE_WIRELESS;
|
|
else if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK_TA)
|
|
val->intval = SEC_BATTERY_CABLE_WIRELESS;
|
|
else if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_STAND)
|
|
val->intval = SEC_BATTERY_CABLE_WIRELESS;
|
|
else if (battery->cable_type == SEC_BATTERY_CABLE_PMA_WIRELESS)
|
|
val->intval = SEC_BATTERY_CABLE_WIRELESS;
|
|
else if (battery->cable_type == SEC_BATTERY_CABLE_WIRELESS_VEHICLE)
|
|
val->intval = SEC_BATTERY_CABLE_WIRELESS;
|
|
else
|
|
val->intval = battery->cable_type;
|
|
pr_info("%s cable type = %d sleep_mode = %d\n", __func__, val->intval, sleep_mode);
|
|
break;
|
|
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
|
val->intval = battery->pdata->technology;
|
|
break;
|
|
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
|
#ifdef CONFIG_SEC_FACTORY
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_NOW, value);
|
|
battery->voltage_now = value.intval;
|
|
dev_err(battery->dev,
|
|
"%s: voltage now(%d)\n", __func__, battery->voltage_now);
|
|
#endif
|
|
/* voltage value should be in uV */
|
|
val->intval = battery->voltage_now * 1000;
|
|
break;
|
|
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
|
|
#ifdef CONFIG_SEC_FACTORY
|
|
value.intval = SEC_BATTERY_VOLTAGE_AVERAGE;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_VOLTAGE_AVG, value);
|
|
battery->voltage_avg = value.intval;
|
|
dev_err(battery->dev,
|
|
"%s: voltage avg(%d)\n", __func__, battery->voltage_avg);
|
|
#endif
|
|
/* voltage value should be in uV */
|
|
val->intval = battery->voltage_avg * 1000;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
|
val->intval = battery->current_now;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
|
val->intval = battery->current_avg;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CHARGE_COUNTER, value);
|
|
val->intval = value.intval;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
|
val->intval = battery->pdata->battery_full_capacity * 1000;
|
|
break;
|
|
/* charging mode (differ from power supply) */
|
|
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
|
val->intval = battery->charging_mode;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CAPACITY:
|
|
if (battery->pdata->fake_capacity) {
|
|
val->intval = 90;
|
|
pr_info("%s : capacity(%d)\n", __func__, val->intval);
|
|
} else {
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
if (battery->status == POWER_SUPPLY_STATUS_FULL) {
|
|
if (battery->eng_not_full_status)
|
|
val->intval = battery->capacity;
|
|
else
|
|
val->intval = 100;
|
|
} else {
|
|
val->intval = battery->capacity;
|
|
}
|
|
#else
|
|
if (battery->status == POWER_SUPPLY_STATUS_FULL)
|
|
val->intval = 100;
|
|
else
|
|
val->intval = battery->capacity;
|
|
#endif
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_TEMP:
|
|
val->intval = battery->temperature;
|
|
break;
|
|
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
|
|
val->intval = battery->temper_amb;
|
|
break;
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
|
|
if (battery->capacity == 100) {
|
|
val->intval = -1;
|
|
break;
|
|
}
|
|
|
|
if (((battery->status == POWER_SUPPLY_STATUS_CHARGING) ||
|
|
(battery->status == POWER_SUPPLY_STATUS_FULL && battery->capacity != 100)) &&
|
|
!battery->swelling_mode)
|
|
val->intval = battery->timetofull;
|
|
else
|
|
val->intval = -1;
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
|
if (battery->swelling_mode)
|
|
val->intval = 1;
|
|
else
|
|
val->intval = 0;
|
|
break;
|
|
#endif
|
|
case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
|
|
val->intval = battery->wire_status;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL:
|
|
case POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL:
|
|
break;
|
|
case POWER_SUPPLY_PROP_POWER_NOW:
|
|
val->intval = battery->charge_power;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int sec_usb_get_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
|
|
if (psp != POWER_SUPPLY_PROP_ONLINE)
|
|
return -EINVAL;
|
|
|
|
if ((battery->health == POWER_SUPPLY_HEALTH_OVERVOLTAGE) ||
|
|
(battery->health == POWER_SUPPLY_HEALTH_UNDERVOLTAGE)) {
|
|
val->intval = 0;
|
|
return 0;
|
|
}
|
|
/* Set enable=1 only if the USB charger is connected */
|
|
switch (battery->wire_status) {
|
|
case SEC_BATTERY_CABLE_USB:
|
|
case SEC_BATTERY_CABLE_USB_CDP:
|
|
val->intval = 1;
|
|
break;
|
|
case SEC_BATTERY_CABLE_PDIC:
|
|
case SEC_BATTERY_CABLE_NONE:
|
|
val->intval = (battery->pd_usb_attached) ? 1:0;
|
|
break;
|
|
default:
|
|
val->intval = 0;
|
|
break;
|
|
}
|
|
|
|
if (battery->slate_mode)
|
|
val->intval = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int sec_ac_get_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
enum power_supply_ext_property ext_psp = psp;
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
if ((battery->health == POWER_SUPPLY_HEALTH_OVERVOLTAGE) ||
|
|
(battery->health == POWER_SUPPLY_HEALTH_UNDERVOLTAGE)) {
|
|
val->intval = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* Set enable=1 only if the AC charger is connected */
|
|
switch (battery->cable_type) {
|
|
case SEC_BATTERY_CABLE_TA:
|
|
case SEC_BATTERY_CABLE_UARTOFF:
|
|
case SEC_BATTERY_CABLE_LAN_HUB:
|
|
case SEC_BATTERY_CABLE_UNKNOWN:
|
|
case SEC_BATTERY_CABLE_PREPARE_TA:
|
|
case SEC_BATTERY_CABLE_9V_ERR:
|
|
case SEC_BATTERY_CABLE_9V_UNKNOWN:
|
|
case SEC_BATTERY_CABLE_9V_TA:
|
|
case SEC_BATTERY_CABLE_12V_TA:
|
|
case SEC_BATTERY_CABLE_HMT_CONNECTED:
|
|
case SEC_BATTERY_CABLE_HMT_CHARGE:
|
|
case SEC_BATTERY_CABLE_HV_TA_CHG_LIMIT:
|
|
case SEC_BATTERY_CABLE_QC20:
|
|
case SEC_BATTERY_CABLE_QC30:
|
|
case SEC_BATTERY_CABLE_TIMEOUT:
|
|
case SEC_BATTERY_CABLE_SMART_OTG:
|
|
case SEC_BATTERY_CABLE_SMART_NOTG:
|
|
case SEC_BATTERY_CABLE_FACTORY_UART:
|
|
val->intval = 1;
|
|
break;
|
|
case SEC_BATTERY_CABLE_PDIC:
|
|
val->intval = (battery->pd_usb_attached) ? 0:1;
|
|
break;
|
|
default:
|
|
val->intval = 0;
|
|
break;
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_TEMP:
|
|
val->intval = battery->chg_temp;
|
|
break;
|
|
case POWER_SUPPLY_PROP_MAX ... POWER_SUPPLY_EXT_PROP_MAX:
|
|
switch (ext_psp) {
|
|
case POWER_SUPPLY_EXT_PROP_WATER_DETECT:
|
|
if (battery->misc_event &
|
|
(BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE | BATT_MISC_EVENT_HICCUP_TYPE)) {
|
|
val->intval = 1;
|
|
pr_info("%s: Water Detect\n", __func__);
|
|
} else {
|
|
val->intval = 0;
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (lpcharge && (battery->misc_event & BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE)) {
|
|
val->intval = 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sec_wireless_get_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
val->intval = is_wireless_type(battery->cable_type) ?
|
|
1 : 0;
|
|
break;
|
|
case POWER_SUPPLY_PROP_PRESENT:
|
|
val->intval = (battery->pdata->wireless_charger_name) ?
|
|
1 : 0;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sec_wireless_set_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
const union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
if (val->intval != SEC_WIRELESS_PAD_NONE &&\
|
|
battery->wc_status == SEC_WIRELESS_PAD_NONE) {
|
|
battery->cisd.data[CISD_DATA_WIRELESS_COUNT]++;
|
|
battery->cisd.data[CISD_DATA_WIRELESS_COUNT_PER_DAY]++;
|
|
}
|
|
#endif
|
|
if (val->intval == SEC_WIRELESS_PAD_A4WP)
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC;
|
|
else
|
|
battery->wc_status = val->intval;
|
|
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
if (battery->wc_status == SEC_WIRELESS_PAD_NONE ||
|
|
battery->wc_status == SEC_WIRELESS_PAD_WPC_PACK ||
|
|
battery->wc_status == SEC_WIRELESS_PAD_WPC_PACK_TA ||
|
|
battery->wc_status == SEC_WIRELESS_PAD_VEHICLE) {
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_WIRELESS_BACKPACK_TYPE,
|
|
(battery->wc_status == SEC_WIRELESS_PAD_NONE));
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_AUTHENTIC:
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
pr_info("%s : tx_type(0x%x)\n", __func__, val->intval);
|
|
|
|
switch (val->intval) {
|
|
case SNGL_NOBLE:
|
|
battery->cisd.wc_data[WC_SNGL_NOBLE]++;
|
|
break;
|
|
case SNGL_VEHICLE:
|
|
battery->cisd.wc_data[WC_SNGL_VEHICLE]++;
|
|
break;
|
|
case SNGL_MINI:
|
|
battery->cisd.wc_data[WC_SNGL_MINI]++;
|
|
break;
|
|
case SNGL_ZERO:
|
|
battery->cisd.wc_data[WC_SNGL_ZERO]++;
|
|
break;
|
|
case SNGL_DREAM:
|
|
battery->cisd.wc_data[WC_SNGL_DREAM]++;
|
|
break;
|
|
case STAND_HERO:
|
|
battery->cisd.wc_data[WC_STAND_HERO]++;
|
|
break;
|
|
case STAND_DREAM:
|
|
battery->cisd.wc_data[WC_STAND_DREAM]++;
|
|
break;
|
|
case EXT_PACK:
|
|
battery->cisd.wc_data[WC_EXT_PACK]++;
|
|
break;
|
|
case EXT_PACK_TA:
|
|
battery->cisd.wc_data[WC_EXT_PACK_TA]++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL:
|
|
if (val->intval) {
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_WPC_VOUT_LOCK,
|
|
SEC_BAT_CURRENT_EVENT_WPC_VOUT_LOCK);
|
|
} else {
|
|
sec_bat_set_current_event(battery, 0,
|
|
SEC_BAT_CURRENT_EVENT_WPC_VOUT_LOCK);
|
|
}
|
|
|
|
if (is_hv_wireless_type(battery->cable_type)) {
|
|
union power_supply_propval value = {0, };
|
|
int cnt;
|
|
|
|
mutex_lock(&battery->iolock);
|
|
value.intval = (val->intval) ? WIRELESS_VOUT_5V :
|
|
battery->wpc_vout_level;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
mutex_unlock(&battery->iolock);
|
|
|
|
for (cnt = 0; cnt < 5; cnt++) {
|
|
msleep(100);
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, value);
|
|
if (value.intval <= 6000) {
|
|
pr_info("%s: wireless vout goes to 5V Vout(%d).\n",
|
|
__func__, value.intval);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sec_ps_set_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
const union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
union power_supply_propval value;
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
if (val->intval == 0 && battery->ps_enable == true) {
|
|
battery->ps_enable = false;
|
|
value.intval = val->intval;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
} else if ((val->intval == 1) && (battery->ps_enable == false) &&
|
|
(battery->ps_status == true)) {
|
|
battery->ps_enable = true;
|
|
value.intval = val->intval;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
} else {
|
|
dev_err(battery->dev,
|
|
"%s: invalid setting (%d)\n", __func__, val->intval);
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
if (val->intval == SEC_BATTERY_CABLE_POWER_SHARING) {
|
|
battery->ps_status = true;
|
|
battery->ps_enable = true;
|
|
value.intval = battery->ps_enable;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
} else {
|
|
battery->ps_status = false;
|
|
battery->ps_enable = false;
|
|
value.intval = battery->ps_enable;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sec_ps_get_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct sec_battery_info *battery = power_supply_get_drvdata(psy);
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
val->intval = (battery->ps_enable) ? 1 : 0;
|
|
break;
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
val->intval = (battery->ps_status) ? 1 : 0;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER) || defined(CONFIG_MUIC_NOTIFIER)
|
|
static int sec_bat_cable_check(struct sec_battery_info *battery,
|
|
muic_attached_dev_t attached_dev)
|
|
{
|
|
int current_cable_type = -1;
|
|
union power_supply_propval val = {0, };
|
|
|
|
pr_info("[%s]ATTACHED(%d)\n", __func__, attached_dev);
|
|
|
|
switch (attached_dev) {
|
|
case ATTACHED_DEV_JIG_UART_OFF_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_ON_MUIC:
|
|
battery->is_jig_on = true;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->skip_cisd = true;
|
|
#endif
|
|
case ATTACHED_DEV_SMARTDOCK_MUIC:
|
|
case ATTACHED_DEV_DESKDOCK_MUIC:
|
|
case ATTACHED_DEV_JIG_USB_ON_MUIC:
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
#if defined(CONFIG_CHARGER_S2MU004) || defined(CONFIG_CHARGER_S2MU005)
|
|
case ATTACHED_DEV_CARKIT_MUIC:
|
|
#endif
|
|
#endif
|
|
current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
break;
|
|
case ATTACHED_DEV_UNDEFINED_CHARGING_MUIC:
|
|
if (battery->pdata->enable_water_resistance) {
|
|
current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_WATER_DETECT]++;
|
|
battery->cisd.data[CISD_DATA_WATER_DETECT_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_SEC_ABC)
|
|
sec_abc_send_event("MODULE=battery@ERROR=water_detect");
|
|
#endif
|
|
} else {
|
|
current_cable_type = SEC_BATTERY_CABLE_TA;
|
|
}
|
|
break;
|
|
case ATTACHED_DEV_UNDEFINED_RANGE_MUIC:
|
|
if (battery->pdata->enable_water_resistance) {
|
|
current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_WATER_DETECT]++;
|
|
battery->cisd.data[CISD_DATA_WATER_DETECT_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_SEC_ABC)
|
|
sec_abc_send_event("MODULE=battery@ERROR=water_detect");
|
|
#endif
|
|
} else if (battery->pdata->detect_moisture) {
|
|
current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
} else {
|
|
current_cable_type = SEC_BATTERY_CABLE_TA;
|
|
}
|
|
break;
|
|
case ATTACHED_DEV_HICCUP_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
break;
|
|
case ATTACHED_DEV_OTG_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC:
|
|
case ATTACHED_DEV_HMT_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_OTG;
|
|
break;
|
|
case ATTACHED_DEV_TIMEOUT_OPEN_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_TIMEOUT;
|
|
break;
|
|
case ATTACHED_DEV_JIG_USB_OFF_MUIC:
|
|
if (!battery->pdata->enable_water_resistance && battery->pdata->detect_moisture)
|
|
current_cable_type = SEC_BATTERY_CABLE_NONE;
|
|
else
|
|
current_cable_type = SEC_BATTERY_CABLE_USB;
|
|
break;
|
|
case ATTACHED_DEV_USB_MUIC:
|
|
case ATTACHED_DEV_SMARTDOCK_USB_MUIC:
|
|
case ATTACHED_DEV_UNOFFICIAL_ID_USB_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_USB;
|
|
break;
|
|
case ATTACHED_DEV_JIG_UART_ON_VB_MUIC:
|
|
current_cable_type = factory_mode ? SEC_BATTERY_CABLE_NONE :
|
|
SEC_BATTERY_CABLE_UARTOFF;
|
|
break;
|
|
case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC:
|
|
if (!battery->pdata->enable_water_resistance && battery->pdata->detect_moisture) {
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT) || defined(CONFIG_SEC_FACTORY)
|
|
current_cable_type = SEC_BATTERY_CABLE_UARTOFF;
|
|
#endif
|
|
} else {
|
|
current_cable_type = factory_mode ? SEC_BATTERY_CABLE_NONE :
|
|
SEC_BATTERY_CABLE_UARTOFF;
|
|
if (battery->block_water_event) {
|
|
if (!(factory_mode))
|
|
current_cable_type = SEC_BATTERY_CABLE_UARTOFF;
|
|
}
|
|
}
|
|
break;
|
|
case ATTACHED_DEV_RDU_TA_MUIC:
|
|
battery->store_mode = true;
|
|
wake_lock(&battery->parse_mode_dt_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->parse_mode_dt_work, 0);
|
|
case ATTACHED_DEV_TA_MUIC:
|
|
case ATTACHED_DEV_CARDOCK_MUIC:
|
|
case ATTACHED_DEV_DESKDOCK_VB_MUIC:
|
|
case ATTACHED_DEV_SMARTDOCK_TA_MUIC:
|
|
case ATTACHED_DEV_UNOFFICIAL_TA_MUIC:
|
|
case ATTACHED_DEV_UNOFFICIAL_ID_TA_MUIC:
|
|
case ATTACHED_DEV_UNOFFICIAL_ID_ANY_MUIC:
|
|
case ATTACHED_DEV_UNSUPPORTED_ID_VB_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_TA;
|
|
break;
|
|
case ATTACHED_DEV_AFC_CHARGER_5V_MUIC:
|
|
case ATTACHED_DEV_QC_CHARGER_5V_MUIC:
|
|
case ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC:
|
|
if (is_hv_wire_type(battery->cable_type) &&
|
|
(battery->chg_limit || battery->vbus_chg_by_siop)) {
|
|
current_cable_type = SEC_BATTERY_CABLE_HV_TA_CHG_LIMIT;
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
} else if (battery->current_event & SEC_BAT_CURRENT_EVENT_AFC &&
|
|
battery->pdic_info.sink_status.rp_currentlvl == RP_CURRENT_LEVEL_DEFAULT) {
|
|
current_cable_type = SEC_BATTERY_CABLE_PREPARE_TA;
|
|
#endif
|
|
} else {
|
|
current_cable_type = SEC_BATTERY_CABLE_TA;
|
|
}
|
|
break;
|
|
case ATTACHED_DEV_CDP_MUIC:
|
|
case ATTACHED_DEV_UNOFFICIAL_ID_CDP_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_USB_CDP;
|
|
break;
|
|
case ATTACHED_DEV_USB_LANHUB_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_LAN_HUB;
|
|
break;
|
|
case ATTACHED_DEV_CHARGING_CABLE_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_POWER_SHARING;
|
|
break;
|
|
case ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC:
|
|
case ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_PREPARE_TA;
|
|
break;
|
|
case ATTACHED_DEV_AFC_CHARGER_9V_MUIC:
|
|
case ATTACHED_DEV_QC_CHARGER_9V_MUIC:
|
|
case ATTACHED_DEV_AFC_CHARGER_9V_DUPLI_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_9V_TA;
|
|
break;
|
|
#if defined(CONFIG_MUIC_HV_12V)
|
|
case ATTACHED_DEV_AFC_CHARGER_12V_MUIC:
|
|
#if 0
|
|
case ATTACHED_DEV_AFC_CHARGER_12V_DUPLI_MUIC:
|
|
#endif
|
|
current_cable_type = SEC_BATTERY_CABLE_12V_TA;
|
|
break;
|
|
#endif
|
|
case ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC:
|
|
case ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC:
|
|
case ATTACHED_DEV_QC_CHARGER_ERR_V_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_9V_ERR;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_AFC_FAIL]++;
|
|
battery->cisd.data[CISD_DATA_AFC_FAIL_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_SEC_ABC)
|
|
sec_abc_send_event("MODULE=battery@ERROR=afc_fail");
|
|
#endif
|
|
break;
|
|
case ATTACHED_DEV_HV_ID_ERR_UNDEFINED_MUIC:
|
|
case ATTACHED_DEV_HV_ID_ERR_UNSUPPORTED_MUIC:
|
|
case ATTACHED_DEV_HV_ID_ERR_SUPPORTED_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_9V_UNKNOWN;
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->cisd.data[CISD_DATA_AFC_FAIL]++;
|
|
battery->cisd.data[CISD_DATA_AFC_FAIL_PER_DAY]++;
|
|
#endif
|
|
#if defined(CONFIG_SEC_ABC)
|
|
sec_abc_send_event("MODULE=battery@ERROR=afc_fail");
|
|
#endif
|
|
break;
|
|
case ATTACHED_DEV_VZW_INCOMPATIBLE_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_UNKNOWN;
|
|
break;
|
|
case ATTACHED_DEV_FACTORY_UART_MUIC:
|
|
current_cable_type = SEC_BATTERY_CABLE_FACTORY_UART;
|
|
break;
|
|
default:
|
|
pr_err("%s: invalid type for charger:%d\n",
|
|
__func__, attached_dev);
|
|
break;
|
|
}
|
|
|
|
#if defined(CONFIG_FUELGAUGE_S2MU004) || defined(CONFIG_FUELGAUGE_S2MU005) || defined(CONFIG_FUELGAUGE_S2MU106) || defined(CONFIG_FUELGAUGE_S2MU205)
|
|
/* If JIG ON is detected then we need to make sure we reset FG on next boot */
|
|
if (battery->is_jig_on)
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, val);
|
|
#else
|
|
#ifndef CONFIG_FUELGAUGE_S2MU005
|
|
if (battery->is_jig_on && !battery->pdata->support_fgsrc_change)
|
|
psy_do_property(battery->pdata->fuelgauge_name, set,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, val);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
#if defined(CONFIG_CHARGER_S2MU004) || defined(CONFIG_CHARGER_S2MU005)
|
|
if (attached_dev == ATTACHED_DEV_JIG_USB_ON_MUIC
|
|
|| attached_dev == ATTACHED_DEV_CARKIT_MUIC
|
|
#if defined(CONFIG_CHARGER_S2MU005)
|
|
|| attached_dev == ATTACHED_DEV_JIG_UART_OFF_MUIC
|
|
|| attached_dev == ATTACHED_DEV_JIG_UART_ON_MUIC
|
|
|| attached_dev == ATTACHED_DEV_JIG_USB_OFF_MUIC
|
|
|| attached_dev == ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC
|
|
|| attached_dev == ATTACHED_DEV_UNDEFINED_RANGE_MUIC
|
|
|| attached_dev == ATTACHED_DEV_HICCUP_MUIC
|
|
#endif
|
|
) {
|
|
val.intval = SEC_BAT_CHG_MODE_BUCK_OFF;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGING_ENABLED, val);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/* s2mu005 : CHG 0xAF[7]=1 for SMPL issue, 0xAF[7]=0 for JIG case */
|
|
#if defined(CONFIG_CHARGER_S2MU005) && !defined(CONFIG_SEC_FACTORY)
|
|
switch (attached_dev) {
|
|
case ATTACHED_DEV_JIG_USB_ON_MUIC:
|
|
val.intval = SEC_BAT_CHG_MODE_BUCK_OFF;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGING_ENABLED, val);
|
|
val.intval = 1;
|
|
break;
|
|
case ATTACHED_DEV_JIG_UART_ON_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_OFF_MUIC:
|
|
case ATTACHED_DEV_JIG_USB_OFF_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC:
|
|
val.intval = 1;
|
|
break;
|
|
default:
|
|
val.intval = 0;
|
|
break;
|
|
}
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, val);
|
|
pr_err("%s : 0xAF work-around execute! (%d)\n", __func__, val.intval);
|
|
#endif
|
|
|
|
#if defined(CONFIG_CHARGER_S2MU106) || defined(CONFIG_CHARGER_S2MU205)
|
|
switch (attached_dev) {
|
|
case ATTACHED_DEV_JIG_USB_ON_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_OFF_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC:
|
|
val.intval = 1;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, val);
|
|
pr_err("%s : FACTORY MODE TEST! (%d)\n", __func__, val.intval);
|
|
break;
|
|
case ATTACHED_DEV_JIG_UART_ON_MUIC:
|
|
case ATTACHED_DEV_JIG_UART_ON_VB_MUIC:
|
|
val.intval = 0;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW, val);
|
|
pr_err("%s : FACTORY MODE TEST! (%d)\n", __func__, val.intval);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return current_cable_type;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
static int sec_bat_get_pd_list_index(PDIC_SINK_STATUS *sink_status, struct sec_bat_pdic_list *pd_list)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < pd_list->max_pd_count; i++) {
|
|
if (pd_list->pd_info[i].pdo_index == sink_status->current_pdo_num)
|
|
return i;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void sec_bat_set_rp_current(struct sec_battery_info *battery, int cable_type)
|
|
{
|
|
if (battery->pdic_info.sink_status.rp_currentlvl == RP_CURRENT_LEVEL3) {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_HV_DISABLE) {
|
|
sec_bat_change_default_current(battery, cable_type,
|
|
battery->pdata->default_input_current, battery->pdata->default_charging_current);
|
|
} else {
|
|
sec_bat_change_default_current(battery, cable_type,
|
|
RP_CURRENT_RP3 > battery->pdata->max_input_current ?
|
|
battery->pdata->max_input_current : RP_CURRENT_RP3, battery->pdata->max_charging_current);
|
|
}
|
|
} else if (battery->pdic_info.sink_status.rp_currentlvl == RP_CURRENT_LEVEL2) {
|
|
sec_bat_change_default_current(battery, cable_type,
|
|
RP_CURRENT_RP2, RP_CURRENT_RP2);
|
|
} else if (cable_type == SEC_BATTERY_CABLE_USB) {
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_USB_SUPER)
|
|
sec_bat_change_default_current(battery, SEC_BATTERY_CABLE_USB,
|
|
USB_CURRENT_SUPER_SPEED, USB_CURRENT_SUPER_SPEED);
|
|
else
|
|
sec_bat_change_default_current(battery, cable_type,
|
|
RP_CURRENT_RP1, RP_CURRENT_RP1);
|
|
}
|
|
|
|
pr_info("%s:(%d)\n", __func__, battery->pdic_info.sink_status.rp_currentlvl);
|
|
battery->max_charge_power = 0;
|
|
sec_bat_set_charging_current(battery);
|
|
}
|
|
#endif
|
|
|
|
static int make_pd_list(struct sec_battery_info *battery)
|
|
{
|
|
int i = 0, pd_list_index = 0, pd_list_select = 0;
|
|
int base_charge_power = 0, selected_pdo_voltage = 0, selected_pdo_power = 0, selected_pdo_num = 0;
|
|
int pd_charging_charge_power = (battery->current_event & SEC_BAT_CURRENT_EVENT_HV_DISABLE) ?
|
|
SEC_INPUT_VOLTAGE_5V * battery->pdata->default_input_current :
|
|
battery->pdata->pd_charging_charge_power;
|
|
|
|
/* If PD charger is attached first, current_pdo_num should be 1 supports 5V */
|
|
battery->pd_list.pd_info[0].input_voltage =
|
|
battery->pdic_info.sink_status.power_list[1].max_voltage;
|
|
battery->pd_list.pd_info[0].input_current =
|
|
battery->pdic_info.sink_status.power_list[1].max_current;
|
|
|
|
battery->pd_list.pd_info[0].pdo_index = 1;
|
|
pd_list_index++;
|
|
|
|
base_charge_power =
|
|
battery->pdic_info.sink_status.power_list[1].max_voltage * battery->pdic_info.sink_status.power_list[1].max_current;
|
|
|
|
selected_pdo_voltage = SEC_INPUT_VOLTAGE_5V * 1000;
|
|
selected_pdo_power = 0;
|
|
selected_pdo_num = 0;
|
|
|
|
for (i = 1; i <= battery->pdic_info.sink_status.available_pdo_num; i++) {
|
|
POWER_LIST* pPower_list = &battery->pdic_info.sink_status.power_list[i];
|
|
int temp_power = pPower_list->max_voltage * pPower_list->max_current;
|
|
|
|
if ((temp_power >= base_charge_power - 1000000) && (temp_power <= pd_charging_charge_power * 1000)) {
|
|
if (temp_power >= selected_pdo_power &&
|
|
pPower_list->max_voltage > selected_pdo_voltage && pPower_list->max_voltage <= battery->pdata->max_input_voltage) {
|
|
selected_pdo_voltage = pPower_list->max_voltage;
|
|
selected_pdo_power = temp_power;
|
|
selected_pdo_num = i;
|
|
}
|
|
}
|
|
}
|
|
if (selected_pdo_num) {
|
|
POWER_LIST* pSelected_power_list =
|
|
&battery->pdic_info.sink_status.power_list[selected_pdo_num];
|
|
|
|
battery->pd_list.pd_info[pd_list_index].pdo_index = selected_pdo_num;
|
|
battery->pd_list.pd_info[pd_list_index].input_voltage = pSelected_power_list->max_voltage;
|
|
battery->pd_list.pd_info[pd_list_index].input_current = pSelected_power_list->max_current;
|
|
pd_list_index++;
|
|
}
|
|
|
|
if (pd_list_index <= 0) {
|
|
pr_info("%s : PDO list is empty!!\n", __func__);
|
|
return 0;
|
|
} else {
|
|
pr_info("%s: total pd_list_index: %d\n", __func__, pd_list_index);
|
|
}
|
|
pd_list_select = pd_list_index - 1;
|
|
|
|
for (i = 0; i < pd_list_index; i++) {
|
|
pr_info("%s: Made pd_list[%d] %s[%d] voltage : %d, current : %d\n",
|
|
__func__, i, i == pd_list_select ? "**" : " ",
|
|
battery->pd_list.pd_info[i].pdo_index,
|
|
battery->pd_list.pd_info[i].input_voltage,
|
|
battery->pd_list.pd_info[i].input_current);
|
|
}
|
|
|
|
battery->pd_list.max_pd_count = pd_list_index;
|
|
battery->max_charge_power = battery->pdic_info.sink_status.power_list[ \
|
|
battery->pd_list.pd_info[pd_list_index-1].pdo_index].max_voltage * \
|
|
battery->pdic_info.sink_status.power_list[battery->pd_list.pd_info[ \
|
|
pd_list_index-1].pdo_index].max_current / 1000;
|
|
battery->pd_max_charge_power = battery->max_charge_power;
|
|
|
|
if (battery->pdic_info.sink_status.selected_pdo_num == battery->pd_list.pd_info[pd_list_index-1].pdo_index) {
|
|
battery->pd_list.now_pd_index = pd_list_index - 1;
|
|
battery->pdic_ps_rdy = true;
|
|
dev_info(battery->dev, "%s: battery->pdic_ps_rdy(%d)\n", __func__, battery->pdic_ps_rdy);
|
|
} else {
|
|
if (battery->pd_list.pd_info[pd_list_select].input_current < battery->input_current) {
|
|
int input_current = battery->pd_list.pd_info[pd_list_select].input_current;
|
|
union power_supply_propval value = {0, };
|
|
|
|
value.intval = input_current;
|
|
battery->input_current = input_current;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CURRENT_MAX, value);
|
|
}
|
|
battery->pdic_ps_rdy = false;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SELECT_PDO,
|
|
SEC_BAT_CURRENT_EVENT_SELECT_PDO);
|
|
battery->pdic_info.sink_status.selected_pdo_num =
|
|
battery->pd_list.pd_info[pd_list_index-1].pdo_index;
|
|
select_pdo(battery->pd_list.pd_info[pd_list_index-1].pdo_index);
|
|
}
|
|
battery->pd_list.now_pd_index = sec_bat_get_pd_list_index(&battery->pdic_info.sink_status,
|
|
&battery->pd_list);
|
|
pr_info("%s : now_pd_index : %d\n", __func__, battery->pd_list.now_pd_index);
|
|
|
|
return battery->pd_list.max_pd_count;
|
|
}
|
|
|
|
static int usb_typec_handle_notification(struct notifier_block *nb,
|
|
unsigned long action, void *data)
|
|
{
|
|
const char *cmd;
|
|
int cable_type = SEC_BATTERY_CABLE_NONE, i = 0, current_pdo = 0;
|
|
struct sec_battery_info *battery =
|
|
container_of(nb, struct sec_battery_info, usb_typec_nb);
|
|
int pd_charging_charge_power = (battery->current_event & SEC_BAT_CURRENT_EVENT_HV_DISABLE) ?
|
|
SEC_INPUT_VOLTAGE_5V * battery->pdata->default_input_current :
|
|
battery->pdata->pd_charging_charge_power;
|
|
CC_NOTI_ATTACH_TYPEDEF usb_typec_info = *(CC_NOTI_ATTACH_TYPEDEF *)data;
|
|
|
|
dev_info(battery->dev, "%s: action (%ld) dump(0x%01x, 0x%01x, 0x%02x, 0x%04x, 0x%04x, 0x%04x)\n",
|
|
__func__, action, usb_typec_info.src, usb_typec_info.dest, usb_typec_info.id,
|
|
usb_typec_info.attach, usb_typec_info.rprd, usb_typec_info.cable_type);
|
|
|
|
if (usb_typec_info.dest != CCIC_NOTIFY_DEV_BATTERY) {
|
|
dev_info(battery->dev, "%s: skip handler dest(%d)\n",
|
|
__func__, usb_typec_info.dest);
|
|
return 0;
|
|
}
|
|
|
|
mutex_lock(&battery->typec_notylock);
|
|
switch (usb_typec_info.id) {
|
|
case CCIC_NOTIFY_ID_WATER:
|
|
case CCIC_NOTIFY_ID_ATTACH:
|
|
switch (usb_typec_info.attach) {
|
|
case MUIC_NOTIFY_CMD_DETACH:
|
|
case MUIC_NOTIFY_CMD_LOGICALLY_DETACH:
|
|
cmd = "DETACH";
|
|
battery->usb_suspend_mode = false;
|
|
battery->is_jig_on = false;
|
|
battery->pd_usb_attached = false;
|
|
cable_type = SEC_BATTERY_CABLE_NONE;
|
|
battery->muic_cable_type = ATTACHED_DEV_NONE_MUIC;
|
|
battery->pdic_info.sink_status.rp_currentlvl = RP_CURRENT_LEVEL_NONE;
|
|
break;
|
|
case MUIC_NOTIFY_CMD_ATTACH:
|
|
case MUIC_NOTIFY_CMD_LOGICALLY_ATTACH:
|
|
/* Skip notify from MUIC if PDIC is attached already */
|
|
if (is_pd_wire_type(battery->wire_status)) {
|
|
mutex_unlock(&battery->typec_notylock);
|
|
return 0;
|
|
}
|
|
cmd = "ATTACH";
|
|
battery->muic_cable_type = usb_typec_info.cable_type;
|
|
cable_type = sec_bat_cable_check(battery, battery->muic_cable_type);
|
|
if (battery->pdic_info.sink_status.rp_currentlvl >= RP_CURRENT_LEVEL_DEFAULT &&
|
|
(cable_type == SEC_BATTERY_CABLE_USB || cable_type == SEC_BATTERY_CABLE_TA)) {
|
|
sec_bat_set_rp_current(battery, cable_type);
|
|
} else if ((struct pdic_notifier_struct *)usb_typec_info.pd != NULL &&
|
|
(*(struct pdic_notifier_struct *)usb_typec_info.pd).event == PDIC_NOTIFY_EVENT_CCIC_ATTACH &&
|
|
(*(struct pdic_notifier_struct *)usb_typec_info.pd).sink_status.rp_currentlvl >= RP_CURRENT_LEVEL_DEFAULT &&
|
|
(cable_type == SEC_BATTERY_CABLE_USB || cable_type == SEC_BATTERY_CABLE_TA)) {
|
|
battery->pdic_info.sink_status.rp_currentlvl =
|
|
(*(struct pdic_notifier_struct *)usb_typec_info.pd).sink_status.rp_currentlvl;
|
|
sec_bat_set_rp_current(battery, cable_type);
|
|
}
|
|
break;
|
|
default:
|
|
cmd = "ERROR";
|
|
cable_type = -1;
|
|
battery->muic_cable_type = usb_typec_info.cable_type;
|
|
break;
|
|
}
|
|
battery->pdic_attach = false;
|
|
battery->pdic_ps_rdy = false;
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
if (battery->muic_cable_type == ATTACHED_DEV_QC_CHARGER_9V_MUIC ||
|
|
battery->muic_cable_type == ATTACHED_DEV_QC_CHARGER_ERR_V_MUIC)
|
|
battery->hv_chg_name = "QC";
|
|
else if (battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_9V_MUIC ||
|
|
battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_9V_DUPLI_MUIC ||
|
|
battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC ||
|
|
battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC)
|
|
battery->hv_chg_name = "AFC";
|
|
#if defined(CONFIG_MUIC_HV_12V)
|
|
else if (battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_12V_MUIC ||
|
|
battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_12V_DUPLI_MUIC)
|
|
battery->hv_chg_name = "12V";
|
|
#endif
|
|
else
|
|
battery->hv_chg_name = "NONE";
|
|
#endif
|
|
break;
|
|
case CCIC_NOTIFY_ID_POWER_STATUS:
|
|
#ifdef CONFIG_SEC_FACTORY
|
|
dev_info(battery->dev, "%s: pd_event(%d)\n", __func__,
|
|
(*(struct pdic_notifier_struct *)usb_typec_info.pd).event);
|
|
#endif
|
|
if ((*(struct pdic_notifier_struct *)usb_typec_info.pd).event == PDIC_NOTIFY_EVENT_DETACH) {
|
|
dev_info(battery->dev, "%s: skip pd operation - attach(%d)\n", __func__, usb_typec_info.attach);
|
|
battery->pdic_attach = false;
|
|
battery->pdic_ps_rdy = false;
|
|
battery->pd_list.now_pd_index = 0;
|
|
mutex_unlock(&battery->typec_notylock);
|
|
return 0;
|
|
} else if ((*(struct pdic_notifier_struct *)usb_typec_info.pd).event == PDIC_NOTIFY_EVENT_PD_PRSWAP_SNKTOSRC) {
|
|
cmd = "PD_PRWAP";
|
|
dev_info(battery->dev, "%s: PRSWAP_SNKTOSRC(%d)\n", __func__, usb_typec_info.attach);
|
|
cable_type = SEC_BATTERY_CABLE_NONE;
|
|
|
|
battery->pdic_attach = false;
|
|
battery->pdic_ps_rdy = false;
|
|
battery->pd_list.now_pd_index = 0;
|
|
goto skip_cable_check;
|
|
}
|
|
|
|
cmd = "PD_ATTACH";
|
|
/* Prevent PD Charge test fail */
|
|
battery->usb_suspend_mode = false;
|
|
|
|
if ((*(struct pdic_notifier_struct *)usb_typec_info.pd).event == PDIC_NOTIFY_EVENT_CCIC_ATTACH) {
|
|
battery->pdic_info.sink_status.rp_currentlvl =
|
|
(*(struct pdic_notifier_struct *)usb_typec_info.pd).sink_status.rp_currentlvl;
|
|
dev_info(battery->dev, "%s: battery->rp_currentlvl(%d)\n", __func__, battery->pdic_info.sink_status.rp_currentlvl);
|
|
if (battery->wire_status == SEC_BATTERY_CABLE_USB || battery->wire_status == SEC_BATTERY_CABLE_TA) {
|
|
cable_type = battery->wire_status;
|
|
battery->chg_limit = false;
|
|
sec_bat_set_rp_current(battery, cable_type);
|
|
goto skip_cable_check;
|
|
}
|
|
mutex_unlock(&battery->typec_notylock);
|
|
return 0;
|
|
}
|
|
if ((*(struct pdic_notifier_struct *)usb_typec_info.pd).event == PDIC_NOTIFY_EVENT_PD_SINK_CAP)
|
|
battery->pdic_attach = false;
|
|
if (!battery->pdic_attach) {
|
|
battery->pdic_info = *(struct pdic_notifier_struct *)usb_typec_info.pd;
|
|
battery->pd_list.now_pd_index = 0;
|
|
} else {
|
|
battery->pdic_info.sink_status.selected_pdo_num =
|
|
(*(struct pdic_notifier_struct *)usb_typec_info.pd).sink_status.selected_pdo_num;
|
|
battery->pdic_info.sink_status.current_pdo_num =
|
|
(*(struct pdic_notifier_struct *)usb_typec_info.pd).sink_status.current_pdo_num;
|
|
battery->pd_list.now_pd_index = sec_bat_get_pd_list_index(&battery->pdic_info.sink_status,
|
|
&battery->pd_list);
|
|
battery->pdic_ps_rdy = true;
|
|
dev_info(battery->dev, "%s: battery->pdic_ps_rdy(%d)\n", __func__, battery->pdic_ps_rdy);
|
|
}
|
|
current_pdo = battery->pdic_info.sink_status.current_pdo_num;
|
|
cable_type = SEC_BATTERY_CABLE_PDIC;
|
|
battery->muic_cable_type = ATTACHED_DEV_NONE_MUIC;
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
battery->hv_chg_name = "PDIC";
|
|
#endif
|
|
battery->input_voltage =
|
|
battery->pdic_info.sink_status.power_list[current_pdo].max_voltage / 1000;
|
|
dev_info(battery->dev, "%s: available pdo : %d, current pdo : %d\n", __func__,
|
|
battery->pdic_info.sink_status.available_pdo_num, current_pdo);
|
|
|
|
for (i=1; i<= battery->pdic_info.sink_status.available_pdo_num; i++) {
|
|
pr_info("%s: power_list[%d], voltage : %d, current : %d, power : %d\n", __func__, i,
|
|
battery->pdic_info.sink_status.power_list[i].max_voltage,
|
|
battery->pdic_info.sink_status.power_list[i].max_current,
|
|
battery->pdic_info.sink_status.power_list[i].max_voltage *
|
|
battery->pdic_info.sink_status.power_list[i].max_current);
|
|
|
|
if ((battery->pdic_info.sink_status.power_list[i].max_voltage *
|
|
battery->pdic_info.sink_status.power_list[i].max_current) >
|
|
(pd_charging_charge_power * 1000)) {
|
|
battery->pdic_info.sink_status.power_list[i].max_current =
|
|
(pd_charging_charge_power * 1000) /
|
|
battery->pdic_info.sink_status.power_list[i].max_voltage;
|
|
|
|
pr_info("%s: ->updated [%d], voltage : %d, current : %d, power : %d\n", __func__, i,
|
|
battery->pdic_info.sink_status.power_list[i].max_voltage,
|
|
battery->pdic_info.sink_status.power_list[i].max_current,
|
|
battery->pdic_info.sink_status.power_list[i].max_voltage *
|
|
battery->pdic_info.sink_status.power_list[i].max_current);
|
|
}
|
|
|
|
}
|
|
if (!battery->pdic_attach) {
|
|
if (make_pd_list(battery) <= 0)
|
|
goto skip_cable_work;
|
|
}
|
|
battery->pdic_attach = true;
|
|
break;
|
|
case CCIC_NOTIFY_ID_USB:
|
|
if (usb_typec_info.cable_type == PD_USB_TYPE) {
|
|
battery->pd_usb_attached = true;
|
|
}
|
|
dev_info(battery->dev, "%s: CCIC_NOTIFY_ID_USB: %d\n",__func__, battery->pd_usb_attached);
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
mutex_unlock(&battery->typec_notylock);
|
|
return 0;
|
|
default:
|
|
cmd = "ERROR";
|
|
cable_type = -1;
|
|
battery->muic_cable_type = ATTACHED_DEV_NONE_MUIC;
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
battery->hv_chg_name = "NONE";
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
skip_cable_check:
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE,
|
|
(battery->muic_cable_type != ATTACHED_DEV_UNDEFINED_CHARGING_MUIC) &&
|
|
(battery->muic_cable_type != ATTACHED_DEV_UNDEFINED_RANGE_MUIC));
|
|
if (battery->muic_cable_type == ATTACHED_DEV_HICCUP_MUIC) {
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_HICCUP_TYPE, 0);
|
|
battery->hiccup_status = 1;
|
|
} else {
|
|
battery->hiccup_status = 0;
|
|
if (battery->misc_event & BATT_MISC_EVENT_HICCUP_TYPE) {
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
}
|
|
}
|
|
|
|
/* showing charging icon and noti(no sound, vi, haptic) only
|
|
* if slow insertion is detected by MUIC
|
|
*/
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_TIMEOUT_OPEN_TYPE,
|
|
(battery->muic_cable_type != ATTACHED_DEV_TIMEOUT_OPEN_MUIC));
|
|
|
|
if (cable_type < 0 || cable_type > SEC_BATTERY_CABLE_MAX) {
|
|
dev_info(battery->dev, "%s: ignore event(%d)\n",
|
|
__func__, battery->muic_cable_type);
|
|
goto skip_cable_work;
|
|
} else if ((cable_type == SEC_BATTERY_CABLE_UNKNOWN) &&
|
|
(battery->status != POWER_SUPPLY_STATUS_DISCHARGING)) {
|
|
battery->cable_type = cable_type;
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
dev_info(battery->dev, "%s: UNKNOWN cable plugin\n", __func__);
|
|
goto skip_cable_work;
|
|
}
|
|
battery->wire_status = cable_type;
|
|
|
|
cancel_delayed_work(&battery->cable_work);
|
|
wake_unlock(&battery->cable_wake_lock);
|
|
|
|
if (cable_type == SEC_BATTERY_CABLE_HV_TA_CHG_LIMIT) {
|
|
/* set current event */
|
|
cancel_delayed_work(&battery->afc_work);
|
|
wake_unlock(&battery->afc_wake_lock);
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_CHG_LIMIT,
|
|
(SEC_BAT_CURRENT_EVENT_CHG_LIMIT | SEC_BAT_CURRENT_EVENT_AFC));
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
battery->polling_count = 1; /* initial value = 1 */
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
} else if ((battery->wire_status == battery->cable_type) &&
|
|
(((battery->wire_status == SEC_BATTERY_CABLE_USB || battery->wire_status == SEC_BATTERY_CABLE_TA) &&
|
|
battery->pdic_info.sink_status.rp_currentlvl > RP_CURRENT_LEVEL_DEFAULT) ||
|
|
is_hv_wire_type(battery->wire_status))) {
|
|
cancel_delayed_work(&battery->afc_work);
|
|
wake_unlock(&battery->afc_wake_lock);
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_AFC);
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
battery->polling_count = 1; /* initial value = 1 */
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
} else if (cable_type == SEC_BATTERY_CABLE_PREPARE_TA) {
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, msecs_to_jiffies(battery->prepare_afc_delay));
|
|
} else {
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
}
|
|
|
|
skip_cable_work:
|
|
dev_info(battery->dev, "%s: CMD[%s], CABLE_TYPE[%d]\n", __func__, cmd, cable_type);
|
|
mutex_unlock(&battery->typec_notylock);
|
|
return 0;
|
|
}
|
|
#else
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
static int batt_pdic_handle_notification(struct notifier_block *nb,
|
|
unsigned long action, void *data)
|
|
{
|
|
const char *cmd;
|
|
struct sec_battery_info *battery =
|
|
container_of(nb, struct sec_battery_info,
|
|
pdic_nb);
|
|
battery->pdic_info = *(struct pdic_notifier_struct *)data;
|
|
|
|
mutex_lock(&battery->batt_handlelock);
|
|
pr_info("%s: pdic_event: %d\n", __func__, battery->pdic_info.event);
|
|
|
|
switch (battery->pdic_info.event) {
|
|
int i, selected_pdo;
|
|
|
|
case PDIC_NOTIFY_EVENT_DETACH:
|
|
cmd = "DETACH";
|
|
battery->pdic_attach = false;
|
|
if (is_pd_wire_type(battery->wire_status)) {
|
|
battery->wire_status = SEC_BATTERY_CABLE_NONE;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
}
|
|
break;
|
|
case PDIC_NOTIFY_EVENT_CCIC_ATTACH:
|
|
cmd = "ATTACH";
|
|
break;
|
|
case PDIC_NOTIFY_EVENT_PD_SINK:
|
|
selected_pdo = battery->pdic_info.sink_status.selected_pdo_num;
|
|
cmd = "ATTACH";
|
|
battery->wire_status = SEC_BATTERY_CABLE_PDIC;
|
|
battery->pdic_attach = true;
|
|
battery->input_voltage =
|
|
battery->pdic_info.sink_status.power_list[selected_pdo].max_voltage / 1000;
|
|
|
|
pr_info("%s: total pdo : %d, selected pdo : %d\n", __func__,
|
|
battery->pdic_info.sink_status.available_pdo_num, selected_pdo);
|
|
for (i = 1; i <= battery->pdic_info.sink_status.available_pdo_num; i++) {
|
|
pr_info("%s: power_list[%d], voltage : %d, current : %d, power : %d\n", __func__, i,
|
|
battery->pdic_info.sink_status.power_list[i].max_voltage,
|
|
battery->pdic_info.sink_status.power_list[i].max_current,
|
|
battery->pdic_info.sink_status.power_list[i].max_voltage *
|
|
battery->pdic_info.sink_status.power_list[i].max_current);
|
|
}
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
break;
|
|
case PDIC_NOTIFY_EVENT_PD_SOURCE:
|
|
cmd = "ATTACH";
|
|
break;
|
|
default:
|
|
cmd = "ERROR";
|
|
break;
|
|
}
|
|
pr_info("%s: CMD=%s, cable_type : %d\n", __func__, cmd, battery->cable_type);
|
|
mutex_unlock(&battery->batt_handlelock);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_MUIC_NOTIFIER)
|
|
static int batt_handle_notification(struct notifier_block *nb,
|
|
unsigned long action, void *data)
|
|
{
|
|
const char *cmd;
|
|
int cable_type = SEC_BATTERY_CABLE_NONE;
|
|
struct sec_battery_info *battery =
|
|
container_of(nb, struct sec_battery_info, batt_nb);
|
|
union power_supply_propval value = {0, };
|
|
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
CC_NOTI_ATTACH_TYPEDEF *p_noti = (CC_NOTI_ATTACH_TYPEDEF *)data;
|
|
muic_attached_dev_t attached_dev = p_noti->cable_type;
|
|
#else
|
|
muic_attached_dev_t attached_dev = *(muic_attached_dev_t *)data;
|
|
#endif
|
|
bool block_water_event = true;
|
|
|
|
mutex_lock(&battery->batt_handlelock);
|
|
switch (action) {
|
|
case MUIC_NOTIFY_CMD_DETACH:
|
|
case MUIC_NOTIFY_CMD_LOGICALLY_DETACH:
|
|
cmd = "DETACH";
|
|
battery->is_jig_on = false;
|
|
cable_type = SEC_BATTERY_CABLE_NONE;
|
|
battery->muic_cable_type = ATTACHED_DEV_NONE_MUIC;
|
|
break;
|
|
case MUIC_NOTIFY_CMD_ATTACH:
|
|
case MUIC_NOTIFY_CMD_LOGICALLY_ATTACH:
|
|
cmd = "ATTACH";
|
|
cable_type = sec_bat_cable_check(battery, attached_dev);
|
|
battery->muic_cable_type = attached_dev;
|
|
break;
|
|
default:
|
|
cmd = "ERROR";
|
|
cable_type = -1;
|
|
battery->muic_cable_type = ATTACHED_DEV_NONE_MUIC;
|
|
break;
|
|
}
|
|
|
|
#if !defined(CONFIG_ENG_BATTERY_CONCEPT) && !defined(CONFIG_SEC_FACTORY)
|
|
pr_info("%s : enable_water_resistance(%d), detect_moisture(%d), block_water_event(%d), muic_cable_type(%d)\n",
|
|
__func__, battery->pdata->enable_water_resistance, battery->pdata->detect_moisture,
|
|
battery->block_water_event, battery->muic_cable_type);
|
|
|
|
if (!battery->pdata->enable_water_resistance && battery->pdata->detect_moisture) {
|
|
/* Block water event UI popup is required for 255k, 301k & 523k cable */
|
|
block_water_event =
|
|
(battery->block_water_event) ||
|
|
((battery->muic_cable_type != ATTACHED_DEV_JIG_USB_OFF_MUIC) &&
|
|
(battery->muic_cable_type != ATTACHED_DEV_JIG_USB_ON_MUIC) &&
|
|
(battery->muic_cable_type != ATTACHED_DEV_JIG_UART_OFF_VB_MUIC) &&
|
|
(battery->muic_cable_type != ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC));
|
|
} else {
|
|
block_water_event = (battery->block_water_event) ||
|
|
((battery->muic_cable_type != ATTACHED_DEV_JIG_UART_ON_MUIC) &&
|
|
(battery->muic_cable_type != ATTACHED_DEV_JIG_USB_ON_MUIC));
|
|
}
|
|
#endif
|
|
|
|
block_water_event &= (battery->muic_cable_type != ATTACHED_DEV_UNDEFINED_RANGE_MUIC);
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE, block_water_event);
|
|
if (battery->muic_cable_type == ATTACHED_DEV_HICCUP_MUIC) {
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_HICCUP_TYPE, 0);
|
|
battery->hiccup_status = 1;
|
|
} else {
|
|
battery->hiccup_status = 0;
|
|
if (battery->misc_event & BATT_MISC_EVENT_HICCUP_TYPE) {
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
}
|
|
}
|
|
|
|
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_TIMEOUT_OPEN_TYPE,
|
|
(battery->muic_cable_type != ATTACHED_DEV_TIMEOUT_OPEN_MUIC));
|
|
|
|
if (attached_dev == ATTACHED_DEV_MHL_MUIC) {
|
|
mutex_unlock(&battery->batt_handlelock);
|
|
return 0;
|
|
}
|
|
|
|
if (cable_type < 0) {
|
|
dev_info(battery->dev, "%s: ignore event(%d)\n",
|
|
__func__, cable_type);
|
|
} else if (cable_type == SEC_BATTERY_CABLE_POWER_SHARING) {
|
|
battery->ps_status = true;
|
|
battery->ps_enable = true;
|
|
battery->wire_status = cable_type;
|
|
dev_info(battery->dev, "%s: power sharing cable plugin\n", __func__);
|
|
} else if (cable_type == SEC_BATTERY_CABLE_WIRELESS) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC_PACK;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_WIRELESS_PACK_TA) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC_PACK_TA;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_HV_WIRELESS) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC_HV;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_WIRELESS_STAND) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC_STAND;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_WIRELESS_HV_STAND) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_WPC_STAND_HV;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_PMA_WIRELESS) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_PMA;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_WIRELESS_VEHICLE) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_VEHICLE;
|
|
} else if (cable_type == SEC_BATTERY_CABLE_WIRELESS_HV_VEHICLE) {
|
|
battery->wc_status = SEC_WIRELESS_PAD_VEHICLE_HV;
|
|
} else if ((cable_type == SEC_BATTERY_CABLE_UNKNOWN) &&
|
|
(battery->status != POWER_SUPPLY_STATUS_DISCHARGING)) {
|
|
battery->cable_type = cable_type;
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
dev_info(battery->dev,
|
|
"%s: UNKNOWN cable plugin\n", __func__);
|
|
mutex_unlock(&battery->batt_handlelock);
|
|
return 0;
|
|
} else {
|
|
battery->wire_status = cable_type;
|
|
if ((battery->wire_status == SEC_BATTERY_CABLE_NONE) &&
|
|
(battery->wc_status) && (!battery->ps_status))
|
|
cable_type = SEC_BATTERY_CABLE_WIRELESS;
|
|
}
|
|
dev_info(battery->dev,
|
|
"%s: current_cable(%d), wc_status(%d), wire_status(%d)\n",
|
|
__func__, cable_type, battery->wc_status,
|
|
battery->wire_status);
|
|
|
|
if (attached_dev == ATTACHED_DEV_USB_LANHUB_MUIC) {
|
|
if (!strcmp(cmd, "ATTACH")) {
|
|
value.intval = true;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL,
|
|
value);
|
|
dev_info(battery->dev,
|
|
"%s: Powered OTG cable attached\n", __func__);
|
|
} else {
|
|
value.intval = false;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL,
|
|
value);
|
|
dev_info(battery->dev,
|
|
"%s: Powered OTG cable detached\n", __func__);
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_AFC_CHARGER_MODE)
|
|
if (!strcmp(cmd, "ATTACH")) {
|
|
if ((battery->muic_cable_type >= ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC) &&
|
|
(battery->muic_cable_type <= ATTACHED_DEV_QC_CHARGER_9V_MUIC)) {
|
|
battery->hv_chg_name = "QC";
|
|
} else if ((battery->muic_cable_type >= ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC) &&
|
|
(battery->muic_cable_type <= ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC)) {
|
|
battery->hv_chg_name = "AFC";
|
|
#if defined(CONFIG_MUIC_HV_12V)
|
|
} else if (battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_12V_MUIC ||
|
|
battery->muic_cable_type == ATTACHED_DEV_AFC_CHARGER_12V_DUPLI_MUIC) {
|
|
battery->hv_chg_name = "12V";
|
|
#endif
|
|
} else
|
|
battery->hv_chg_name = "NONE";
|
|
} else {
|
|
battery->hv_chg_name = "NONE";
|
|
}
|
|
|
|
pr_info("%s : HV_CHARGER_NAME(%s)\n",
|
|
__func__, battery->hv_chg_name);
|
|
#endif
|
|
|
|
if ((cable_type >= 0) &&
|
|
cable_type <= SEC_BATTERY_CABLE_MAX) {
|
|
if (cable_type == SEC_BATTERY_CABLE_POWER_SHARING) {
|
|
value.intval = battery->ps_enable;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
} else if ((cable_type == SEC_BATTERY_CABLE_NONE) && (battery->ps_status)) {
|
|
if (battery->ps_enable) {
|
|
battery->ps_enable = false;
|
|
value.intval = battery->ps_enable;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value);
|
|
}
|
|
battery->ps_status = false;
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
} else if (cable_type != battery->cable_type) {
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->cable_work, 0);
|
|
} else {
|
|
dev_info(battery->dev,
|
|
"%s: Cable is Not Changed(%d)\n",
|
|
__func__, battery->cable_type);
|
|
}
|
|
}
|
|
|
|
pr_info("%s: CMD=%s, attached_dev=%d\n", __func__, cmd, attached_dev);
|
|
mutex_unlock(&battery->batt_handlelock);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_MUIC_NOTIFIER */
|
|
#endif
|
|
|
|
#if defined(CONFIG_VBUS_NOTIFIER)
|
|
static int vbus_handle_notification(struct notifier_block *nb,
|
|
unsigned long action, void *data)
|
|
{
|
|
vbus_status_t vbus_status = *(vbus_status_t *)data;
|
|
struct sec_battery_info *battery =
|
|
container_of(nb, struct sec_battery_info, vbus_nb);
|
|
union power_supply_propval value = {0, };
|
|
|
|
mutex_lock(&battery->batt_handlelock);
|
|
if (battery->muic_cable_type == ATTACHED_DEV_HMT_MUIC &&
|
|
battery->muic_vbus_status != vbus_status &&
|
|
battery->muic_vbus_status == STATUS_VBUS_HIGH &&
|
|
vbus_status == STATUS_VBUS_LOW) {
|
|
msleep(500);
|
|
value.intval = true;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
|
|
value);
|
|
dev_info(battery->dev,
|
|
"%s: changed to OTG cable attached\n", __func__);
|
|
|
|
battery->wire_status = SEC_BATTERY_CABLE_OTG;
|
|
wake_lock(&battery->cable_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->cable_work, 0);
|
|
}
|
|
pr_info("%s: action=%d, vbus_status=%d\n", __func__, (int)action, vbus_status);
|
|
mutex_unlock(&battery->batt_handlelock);
|
|
battery->muic_vbus_status = vbus_status;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_OF
|
|
static int sec_bat_parse_dt(struct device *dev,
|
|
struct sec_battery_info *battery)
|
|
{
|
|
struct device_node *np;
|
|
sec_battery_platform_data_t *pdata = battery->pdata;
|
|
int ret = 0, len = 0;
|
|
unsigned int i = 0;
|
|
const u32 *p;
|
|
u32 temp = 0;
|
|
|
|
np = of_find_node_by_name(NULL, "cable-info");
|
|
if (!np) {
|
|
pr_err ("%s : np NULL\n", __func__);
|
|
} else {
|
|
struct device_node *child;
|
|
u32 input_current = 0, charging_current = 0;
|
|
|
|
ret = of_property_read_u32(np, "default_input_current", &input_current);
|
|
ret = of_property_read_u32(np, "default_charging_current", &charging_current);
|
|
ret = of_property_read_u32(np, "full_check_current_1st", &pdata->full_check_current_1st);
|
|
ret = of_property_read_u32(np, "full_check_current_2nd", &pdata->full_check_current_2nd);
|
|
|
|
pdata->default_input_current = input_current;
|
|
pdata->default_charging_current = charging_current;
|
|
pdata->charging_current =
|
|
kzalloc(sizeof(sec_charging_current_t) * SEC_BATTERY_CABLE_MAX,
|
|
GFP_KERNEL);
|
|
|
|
for (i = 0; i < SEC_BATTERY_CABLE_MAX; i++) {
|
|
pdata->charging_current[i].input_current_limit = (unsigned int)input_current;
|
|
pdata->charging_current[i].fast_charging_current = (unsigned int)charging_current;
|
|
}
|
|
|
|
for_each_child_of_node(np, child) {
|
|
ret = of_property_read_u32(child, "input_current", &input_current);
|
|
ret = of_property_read_u32(child, "charging_current", &charging_current);
|
|
|
|
p = of_get_property(child, "cable_number", &len);
|
|
if (!p)
|
|
return 1;
|
|
|
|
len = len / sizeof(u32);
|
|
|
|
for (i = 0; i <= len; i++) {
|
|
ret = of_property_read_u32_index(child, "cable_number", i, &temp);
|
|
pdata->charging_current[temp].input_current_limit = (unsigned int)input_current;
|
|
pdata->charging_current[temp].fast_charging_current = (unsigned int)charging_current;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < SEC_BATTERY_CABLE_MAX; i++) {
|
|
pr_info("%s : CABLE_NUM(%d) INPUT(%d) CHARGING(%d)\n",
|
|
__func__, i,
|
|
pdata->charging_current[i].input_current_limit,
|
|
pdata->charging_current[i].fast_charging_current);
|
|
}
|
|
|
|
pr_info("%s : TOPOFF_1ST(%d), TOPOFF_2ND(%d)\n",
|
|
__func__, pdata->full_check_current_1st, pdata->full_check_current_2nd);
|
|
#ifdef CONFIG_SEC_FACTORY
|
|
pdata->charging_current[SEC_BATTERY_CABLE_TA].fast_charging_current = 1500;
|
|
#endif
|
|
|
|
pdata->default_usb_output_current = pdata->charging_current[SEC_BATTERY_CABLE_USB].fast_charging_current;
|
|
pdata->default_ta_input_current = pdata->charging_current[SEC_BATTERY_CABLE_TA].input_current_limit;
|
|
pdata->default_ta_output_current = pdata->charging_current[SEC_BATTERY_CABLE_TA].fast_charging_current;
|
|
|
|
np = of_find_node_by_name(NULL, "battery");
|
|
if (!np) {
|
|
pr_info("%s: np NULL\n", __func__);
|
|
return 1;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,battery_full_capacity",
|
|
&pdata->battery_full_capacity);
|
|
if (ret) {
|
|
pr_info("%s : battery_full_capacity is Empty\n", __func__);
|
|
}
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
else {
|
|
pr_info("%s : battery_full_capacity : %d\n", __func__, pdata->battery_full_capacity);
|
|
pdata->cisd_cap_high_thr = pdata->battery_full_capacity + 1000;
|
|
pdata->cisd_cap_low_thr = pdata->battery_full_capacity + 500;
|
|
pdata->cisd_cap_limit = (pdata->battery_full_capacity * 11) / 10;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,cisd_max_voltage_thr",
|
|
&pdata->max_voltage_thr);
|
|
if (ret) {
|
|
pr_info("%s : cisd_max_voltage_thr is Empty\n", __func__);
|
|
pdata->max_voltage_thr = 4400;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,cisd_alg_index",
|
|
&pdata->cisd_alg_index);
|
|
if (ret) {
|
|
pr_info("%s : cisd_alg_index is Empty. Defalut set to six\n", __func__);
|
|
pdata->cisd_alg_index = 6;
|
|
} else {
|
|
pr_info("%s : set cisd_alg_index : %d\n", __func__, pdata->cisd_alg_index);
|
|
}
|
|
#endif
|
|
|
|
ret = of_property_read_u32(np,
|
|
"battery,expired_time", &temp);
|
|
if (ret) {
|
|
pr_info("expired time is empty\n");
|
|
pdata->expired_time = 3 * 60 * 60;
|
|
} else {
|
|
pdata->expired_time = (unsigned int) temp;
|
|
}
|
|
pdata->expired_time *= 1000;
|
|
battery->expired_time = pdata->expired_time;
|
|
|
|
ret = of_property_read_u32(np,
|
|
"battery,recharging_expired_time", &temp);
|
|
if (ret) {
|
|
pr_info("expired time is empty\n");
|
|
pdata->recharging_expired_time = 90 * 60;
|
|
} else {
|
|
pdata->recharging_expired_time = (unsigned int) temp;
|
|
}
|
|
pdata->recharging_expired_time *= 1000;
|
|
|
|
ret = of_property_read_u32(np,
|
|
"battery,standard_curr", &pdata->standard_curr);
|
|
if (ret) {
|
|
pr_info("standard_curr is empty\n");
|
|
pdata->standard_curr = 2150;
|
|
}
|
|
|
|
ret = of_property_read_string(np,
|
|
"battery,vendor", (char const **)&pdata->vendor);
|
|
if (ret)
|
|
pr_info("%s: Vendor is Empty\n", __func__);
|
|
|
|
ret = of_property_read_string(np,
|
|
"battery,charger_name", (char const **)&pdata->charger_name);
|
|
if (ret)
|
|
pr_info("%s: Charger name is Empty\n", __func__);
|
|
|
|
ret = of_property_read_string(np,
|
|
"battery,fuelgauge_name", (char const **)&pdata->fuelgauge_name);
|
|
if (ret)
|
|
pr_info("%s: Fuelgauge name is Empty\n", __func__);
|
|
|
|
#if defined(CONFIG_SEC_FACTORY) &&\
|
|
(defined(CONFIG_FUELGAUGE_S2MU004) || defined(CONFIG_FUELGAUGE_S2MU005))
|
|
ret = of_property_read_string(np,
|
|
"battery,fuelgauge_name", (char const **)&pdata->fgsrc_switch_name);
|
|
if (ret)
|
|
pr_info("%s: fgsrc_switch_name is Empty\n", __func__);
|
|
else
|
|
pdata->support_fgsrc_change = true;
|
|
#else
|
|
ret = of_property_read_string(np,
|
|
"battery,fgsrc_switch_name", (char const **)&pdata->fgsrc_switch_name);
|
|
if (ret) {
|
|
pdata->support_fgsrc_change = false;
|
|
pr_info("%s: fgsrc_switch_name is Empty\n", __func__);
|
|
}
|
|
else
|
|
pdata->support_fgsrc_change = true;
|
|
#endif
|
|
|
|
ret = of_property_read_string(np,
|
|
"battery,wireless_charger_name", (char const **)&pdata->wireless_charger_name);
|
|
if (ret)
|
|
pr_info("%s: Wireless charger name is Empty\n", __func__);
|
|
|
|
ret = of_property_read_string(np,
|
|
"battery,chip_vendor", (char const **)&pdata->chip_vendor);
|
|
if (ret)
|
|
pr_info("%s: Chip vendor is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,technology",
|
|
&pdata->technology);
|
|
if (ret)
|
|
pr_info("%s : technology is Empty\n", __func__);
|
|
|
|
pdata->enable_water_resistance = of_property_read_bool(np,
|
|
"battery,enable_water_resistance");
|
|
|
|
ret = of_property_read_u32(np,
|
|
"battery,wireless_cc_cv", &pdata->wireless_cc_cv);
|
|
|
|
pdata->fake_capacity = of_property_read_bool(np,
|
|
"battery,fake_capacity");
|
|
|
|
pdata->detect_moisture = of_property_read_bool(np, "battery,detect_moisture");
|
|
pr_info("%s : detect_moisture = %d \n", __func__, pdata->detect_moisture);
|
|
|
|
p = of_get_property(np, "battery,polling_time", &len);
|
|
if (!p)
|
|
return 1;
|
|
|
|
len = len / sizeof(u32);
|
|
pdata->polling_time = kzalloc(sizeof(*pdata->polling_time) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,polling_time",
|
|
pdata->polling_time, len);
|
|
if (ret)
|
|
pr_info("%s : battery,polling_time is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,thermal_source",
|
|
&pdata->thermal_source);
|
|
if (ret)
|
|
pr_info("%s : Thermal source is Empty\n", __func__);
|
|
|
|
if (pdata->thermal_source == SEC_BATTERY_THERMAL_SOURCE_ADC) {
|
|
p = of_get_property(np, "battery,temp_table_adc", &len);
|
|
if (!p)
|
|
return 1;
|
|
|
|
len = len / sizeof(u32);
|
|
|
|
pdata->temp_adc_table_size = len;
|
|
pdata->temp_amb_adc_table_size = len;
|
|
|
|
pdata->temp_adc_table =
|
|
kzalloc(sizeof(sec_bat_adc_table_data_t) *
|
|
pdata->temp_adc_table_size, GFP_KERNEL);
|
|
pdata->temp_amb_adc_table =
|
|
kzalloc(sizeof(sec_bat_adc_table_data_t) *
|
|
pdata->temp_adc_table_size, GFP_KERNEL);
|
|
|
|
for (i = 0; i < pdata->temp_adc_table_size; i++) {
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,temp_table_adc", i, &temp);
|
|
pdata->temp_adc_table[i].adc = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp_adc_table(adc) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,temp_table_data", i, &temp);
|
|
pdata->temp_adc_table[i].data = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp_adc_table(data) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,temp_table_adc", i, &temp);
|
|
pdata->temp_amb_adc_table[i].adc = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp_amb_adc_table(adc) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,temp_table_data", i, &temp);
|
|
pdata->temp_amb_adc_table[i].data = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp_amb_adc_table(data) is Empty\n",
|
|
__func__);
|
|
}
|
|
}
|
|
ret = of_property_read_u32(np, "battery,usb_thermal_source",
|
|
&pdata->usb_thermal_source);
|
|
if (ret)
|
|
pr_info("%s : usb_thermal_source is Empty\n", __func__);
|
|
|
|
if (pdata->usb_thermal_source) {
|
|
p = of_get_property(np, "battery,usb_temp_table_adc", &len);
|
|
if (!p)
|
|
return 1;
|
|
|
|
len = len / sizeof(u32);
|
|
|
|
pdata->usb_temp_adc_table_size = len;
|
|
|
|
pdata->usb_temp_adc_table =
|
|
kzalloc(sizeof(sec_bat_adc_table_data_t) *
|
|
pdata->usb_temp_adc_table_size, GFP_KERNEL);
|
|
|
|
for (i = 0; i < pdata->usb_temp_adc_table_size; i++) {
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,usb_temp_table_adc", i, &temp);
|
|
pdata->usb_temp_adc_table[i].adc = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Usb_Temp_adc_table(adc) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,usb_temp_table_data", i, &temp);
|
|
pdata->usb_temp_adc_table[i].data = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Usb_Temp_adc_table(data) is Empty\n",
|
|
__func__);
|
|
}
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_thermal_source",
|
|
&pdata->chg_thermal_source);
|
|
if (ret)
|
|
pr_info("%s : chg_thermal_source is Empty\n", __func__);
|
|
|
|
if (pdata->chg_thermal_source == SEC_CHARGER_THERMAL_SOURCE_ADC) {
|
|
p = of_get_property(np, "battery,chg_temp_table_adc", &len);
|
|
if (!p)
|
|
return 1;
|
|
|
|
len = len / sizeof(u32);
|
|
|
|
pdata->chg_temp_adc_table_size = len;
|
|
|
|
pdata->chg_temp_adc_table =
|
|
kzalloc(sizeof(sec_bat_adc_table_data_t) *
|
|
pdata->chg_temp_adc_table_size, GFP_KERNEL);
|
|
|
|
for (i = 0; i < pdata->chg_temp_adc_table_size; i++) {
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,chg_temp_table_adc", i, &temp);
|
|
pdata->chg_temp_adc_table[i].adc = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : CHG_Temp_adc_table(adc) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,chg_temp_table_data", i, &temp);
|
|
pdata->chg_temp_adc_table[i].data = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : CHG_Temp_adc_table(data) is Empty\n",
|
|
__func__);
|
|
}
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_thermal_source",
|
|
&pdata->wpc_thermal_source);
|
|
if (ret)
|
|
pr_info("%s : wpc_thermal_source is Empty\n", __func__);
|
|
|
|
if (pdata->wpc_thermal_source) {
|
|
p = of_get_property(np, "battery,wpc_temp_table_adc", &len);
|
|
if (!p) {
|
|
pr_info("%s : wpc_temp_table_adc(adc) is Empty\n",__func__);
|
|
} else {
|
|
len = len / sizeof(u32);
|
|
|
|
pdata->wpc_temp_adc_table_size = len;
|
|
|
|
pdata->wpc_temp_adc_table =
|
|
kzalloc(sizeof(sec_bat_adc_table_data_t) *
|
|
pdata->wpc_temp_adc_table_size, GFP_KERNEL);
|
|
|
|
for (i = 0; i < pdata->wpc_temp_adc_table_size; i++) {
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,wpc_temp_table_adc", i, &temp);
|
|
pdata->wpc_temp_adc_table[i].adc = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : WPC_Temp_adc_table(adc) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,wpc_temp_table_data", i, &temp);
|
|
pdata->wpc_temp_adc_table[i].data = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : WPC_Temp_adc_table(data) is Empty\n",
|
|
__func__);
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,coil_thermal_source",
|
|
&pdata->coil_thermal_source);
|
|
if (ret)
|
|
pr_info("%s : coil_thermal_source is Empty\n", __func__);
|
|
else
|
|
pr_info("%s : coil_thermal_source exists\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,slave_thermal_source",
|
|
&pdata->slave_thermal_source);
|
|
if (ret)
|
|
pr_info("%s : slave_thermal_source is Empty\n", __func__);
|
|
|
|
if (pdata->slave_thermal_source) {
|
|
p = of_get_property(np, "battery,slave_chg_temp_table_adc", &len);
|
|
if (!p)
|
|
return 1;
|
|
|
|
len = len / sizeof(u32);
|
|
|
|
pdata->slave_chg_temp_adc_table_size = len;
|
|
|
|
pdata->slave_chg_temp_adc_table =
|
|
kzalloc(sizeof(sec_bat_adc_table_data_t) *
|
|
pdata->slave_chg_temp_adc_table_size, GFP_KERNEL);
|
|
|
|
for (i = 0; i < pdata->slave_chg_temp_adc_table_size; i++) {
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,slave_chg_temp_table_adc", i, &temp);
|
|
pdata->slave_chg_temp_adc_table[i].adc = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : slave_chg_temp_adc_table(adc) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,slave_chg_temp_table_data", i, &temp);
|
|
pdata->slave_chg_temp_adc_table[i].data = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : slave_chg_temp_adc_table(data) is Empty\n",
|
|
__func__);
|
|
}
|
|
}
|
|
ret = of_property_read_u32(np, "battery,slave_chg_temp_check",
|
|
&pdata->slave_chg_temp_check);
|
|
if (ret)
|
|
pr_info("%s : slave_chg_temp_check is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_temp_check",
|
|
&pdata->chg_temp_check);
|
|
if (ret)
|
|
pr_info("%s : chg_temp_check is Empty\n", __func__);
|
|
|
|
if (pdata->chg_temp_check) {
|
|
ret = of_property_read_u32(np, "battery,chg_heating_prevention_method",
|
|
&pdata->chg_heating_prevention_method);
|
|
if (ret) {
|
|
pr_info("%s : chg_heating_prevention_method is Empty\n", __func__);
|
|
pdata->chg_heating_prevention_method = 0;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_12v_high_temp",
|
|
&temp);
|
|
pdata->chg_12v_high_temp = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : chg_12v_high_temp is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_high_temp",
|
|
&temp);
|
|
pdata->chg_high_temp = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : chg_high_temp is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_high_temp_recovery",
|
|
&temp);
|
|
pdata->chg_high_temp_recovery = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : chg_temp_recovery is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_charging_limit_current",
|
|
&pdata->chg_charging_limit_current);
|
|
if (ret)
|
|
pr_info("%s : chg_charging_limit_current is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_input_limit_current",
|
|
&pdata->chg_input_limit_current);
|
|
if (ret)
|
|
pr_info("%s : chg_input_limit_current is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,mix_high_temp",
|
|
&pdata->mix_high_temp);
|
|
if (ret)
|
|
pr_info("%s : mix_high_temp is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,mix_high_chg_temp",
|
|
&pdata->mix_high_chg_temp);
|
|
if (ret)
|
|
pr_info("%s : mix_high_chg_temp is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,mix_high_temp_recovery",
|
|
&pdata->mix_high_temp_recovery);
|
|
if (ret)
|
|
pr_info("%s : mix_high_temp_recovery is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,mix_high_chg_temp_recovery",
|
|
&pdata->mix_high_chg_temp_recovery );
|
|
if (ret)
|
|
pr_info("%s : mix_high_chg_temp_recovery is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,mix_temp_input_current",
|
|
&pdata->mix_temp_input_current);
|
|
if (ret)
|
|
pr_info("%s : mix_temp_input_current is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,mix_temp_charging_current",
|
|
&pdata->mix_temp_charging_current);
|
|
if (ret)
|
|
pr_info("%s : mix_temp_charging_current is Empty\n", __func__);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_temp_check",
|
|
&pdata->wpc_temp_check);
|
|
if (ret)
|
|
pr_info("%s : wpc_temp_check is Empty\n", __func__);
|
|
|
|
if (pdata->wpc_temp_check) {
|
|
ret = of_property_read_u32(np, "battery,wpc_temp_control_source",
|
|
&pdata->wpc_temp_control_source);
|
|
if (ret) {
|
|
pr_info("%s : wpc_temp_control_source is Empty\n", __func__);
|
|
pdata->wpc_temp_control_source = TEMP_CONTROL_SOURCE_CHG_THM;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_high_temp",
|
|
&pdata->wpc_high_temp);
|
|
if (ret)
|
|
pr_info("%s : wpc_high_temp is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_high_temp_recovery",
|
|
&pdata->wpc_high_temp_recovery);
|
|
if (ret)
|
|
pr_info("%s : wpc_high_temp_recovery is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_charging_limit_current",
|
|
&pdata->wpc_charging_limit_current);
|
|
if (ret)
|
|
pr_info("%s : wpc_charging_limit_current is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_lcd_on_high_temp",
|
|
&pdata->wpc_lcd_on_high_temp);
|
|
if (ret)
|
|
pr_info("%s : wpc_lcd_on_high_temp is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_lcd_on_high_temp_rec",
|
|
&pdata->wpc_lcd_on_high_temp_rec);
|
|
if (ret)
|
|
pr_info("%s : wpc_lcd_on_high_temp_rec is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_lcd_on_charging_limit_current",
|
|
&pdata->wpc_lcd_on_charging_limit_current);
|
|
if (ret) {
|
|
pr_info("%s : wpc_lcd_on_charging_limit_current is Empty\n", __func__);
|
|
pdata->wpc_lcd_on_charging_limit_current =
|
|
pdata->wpc_charging_limit_current;
|
|
}
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wc_full_input_limit_current",
|
|
&pdata->wc_full_input_limit_current);
|
|
if (ret)
|
|
pr_info("%s : wc_full_input_limit_current is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wc_cv_current",
|
|
&pdata->wc_cv_current);
|
|
if (ret)
|
|
pr_info("%s : wc_cv_current is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wc_cv_pack_current",
|
|
&pdata->wc_cv_pack_current);
|
|
if (ret) {
|
|
pr_info("%s : wc_cv_pack_current is Empty\n", __func__);
|
|
pdata->wc_cv_pack_current = 500;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wc_hero_stand_cc_cv",
|
|
&pdata->wc_hero_stand_cc_cv);
|
|
if (ret) {
|
|
pr_info("%s : wc_hero_stand_cc_cv is Empty\n", __func__);
|
|
pdata->wc_hero_stand_cc_cv = 70;
|
|
}
|
|
ret = of_property_read_u32(np, "battery,wc_hero_stand_cv_current",
|
|
&pdata->wc_hero_stand_cv_current);
|
|
if (ret) {
|
|
pr_info("%s : wc_hero_stand_cv_current is Empty\n", __func__);
|
|
pdata->wc_hero_stand_cv_current = 600;
|
|
}
|
|
ret = of_property_read_u32(np, "battery,wc_hero_stand_hv_cv_current",
|
|
&pdata->wc_hero_stand_hv_cv_current);
|
|
if (ret) {
|
|
pr_info("%s : wc_hero_stand_hv_cv_current is Empty\n", __func__);
|
|
pdata->wc_hero_stand_hv_cv_current = 450;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,sleep_mode_limit_current",
|
|
&pdata->sleep_mode_limit_current);
|
|
if (ret)
|
|
pr_info("%s : sleep_mode_limit_current is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,inbat_voltage",
|
|
&pdata->inbat_voltage);
|
|
if (ret)
|
|
pr_info("%s : inbat_voltage is Empty\n", __func__);
|
|
|
|
if (pdata->inbat_voltage) {
|
|
p = of_get_property(np, "battery,inbat_voltage_table_adc", &len);
|
|
if (!p)
|
|
return 1;
|
|
|
|
len = len / sizeof(u32);
|
|
|
|
pdata->inbat_adc_table_size = len;
|
|
|
|
pdata->inbat_adc_table =
|
|
kzalloc(sizeof(sec_bat_adc_table_data_t) *
|
|
pdata->inbat_adc_table_size, GFP_KERNEL);
|
|
|
|
for (i = 0; i < pdata->inbat_adc_table_size; i++) {
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,inbat_voltage_table_adc", i, &temp);
|
|
pdata->inbat_adc_table[i].adc = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : inbat_adc_table(adc) is Empty\n",
|
|
__func__);
|
|
|
|
ret = of_property_read_u32_index(np,
|
|
"battery,inbat_voltage_table_data", i, &temp);
|
|
pdata->inbat_adc_table[i].data = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : inbat_adc_table(data) is Empty\n",
|
|
__func__);
|
|
}
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,pre_afc_input_current",
|
|
&pdata->pre_afc_input_current);
|
|
if (ret) {
|
|
pr_info("%s : pre_afc_input_current is Empty\n", __func__);
|
|
pdata->pre_afc_input_current = 1000;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,pre_afc_work_delay",
|
|
&pdata->pre_afc_work_delay);
|
|
if (ret) {
|
|
pr_info("%s : pre_afc_work_delay is Empty\n", __func__);
|
|
pdata->pre_afc_work_delay = 2000;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,pre_wc_afc_input_current",
|
|
&pdata->pre_wc_afc_input_current);
|
|
if (ret) {
|
|
pr_info("%s : pre_wc_afc_input_current is Empty\n", __func__);
|
|
pdata->pre_wc_afc_input_current = 500; /* wc input default */
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,pre_wc_afc_work_delay",
|
|
&pdata->pre_wc_afc_work_delay);
|
|
if (ret) {
|
|
pr_info("%s : pre_wc_afc_work_delay is Empty\n", __func__);
|
|
pdata->pre_wc_afc_work_delay = 4000;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,adc_check_count",
|
|
&pdata->adc_check_count);
|
|
if (ret)
|
|
pr_info("%s : Adc check count is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_adc_type",
|
|
&pdata->temp_adc_type);
|
|
if (ret)
|
|
pr_info("%s : Temp adc type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,cable_check_type",
|
|
&pdata->cable_check_type);
|
|
if (ret)
|
|
pr_info("%s : Cable check type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,cable_source_type",
|
|
&pdata->cable_source_type);
|
|
#if defined(CONFIG_CHARGING_VZWCONCEPT)
|
|
pdata->cable_check_type &= ~SEC_BATTERY_CABLE_CHECK_NOUSBCHARGE;
|
|
pdata->cable_check_type |= SEC_BATTERY_CABLE_CHECK_NOINCOMPATIBLECHARGE;
|
|
#endif
|
|
if (ret)
|
|
pr_info("%s : Cable source type is Empty\n", __func__);
|
|
ret = of_property_read_u32(np, "battery,polling_type",
|
|
&pdata->polling_type);
|
|
if (ret)
|
|
pr_info("%s : Polling type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,monitor_initial_count",
|
|
&pdata->monitor_initial_count);
|
|
if (ret)
|
|
pr_info("%s : Monitor initial count is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,battery_check_type",
|
|
&pdata->battery_check_type);
|
|
if (ret)
|
|
pr_info("%s : Battery check type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,check_count",
|
|
&pdata->check_count);
|
|
if (ret)
|
|
pr_info("%s : Check count is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,check_adc_max",
|
|
&pdata->check_adc_max);
|
|
if (ret)
|
|
pr_info("%s : Check adc max is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,check_adc_min",
|
|
&pdata->check_adc_min);
|
|
if (ret)
|
|
pr_info("%s : Check adc min is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,ovp_uvlo_check_type",
|
|
&pdata->ovp_uvlo_check_type);
|
|
if (ret)
|
|
pr_info("%s : Ovp Uvlo check type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_check_type",
|
|
&pdata->temp_check_type);
|
|
if (ret)
|
|
pr_info("%s : Temp check type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_check_count",
|
|
&pdata->temp_check_count);
|
|
if (ret)
|
|
pr_info("%s : Temp check count is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_highlimit_threshold_normal",
|
|
&temp);
|
|
pdata->temp_highlimit_threshold_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp highlimit threshold normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_highlimit_recovery_normal",
|
|
&temp);
|
|
pdata->temp_highlimit_recovery_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp highlimit recovery normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_high_threshold_normal",
|
|
&temp);
|
|
pdata->temp_high_threshold_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp high threshold normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_high_recovery_normal",
|
|
&temp);
|
|
pdata->temp_high_recovery_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp high recovery normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_low_threshold_normal",
|
|
&temp);
|
|
pdata->temp_low_threshold_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp low threshold normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_low_recovery_normal",
|
|
&temp);
|
|
pdata->temp_low_recovery_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp low recovery normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_highlimit_threshold_lpm",
|
|
&temp);
|
|
pdata->temp_highlimit_threshold_lpm = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp highlimit threshold lpm is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_highlimit_recovery_lpm",
|
|
&temp);
|
|
pdata->temp_highlimit_recovery_lpm = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp highlimit recovery lpm is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_high_threshold_lpm",
|
|
&temp);
|
|
pdata->temp_high_threshold_lpm = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp high threshold lpm is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_high_recovery_lpm",
|
|
&temp);
|
|
pdata->temp_high_recovery_lpm = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp high recovery lpm is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_low_threshold_lpm",
|
|
&temp);
|
|
pdata->temp_low_threshold_lpm = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp low threshold lpm is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,temp_low_recovery_lpm",
|
|
&temp);
|
|
pdata->temp_low_recovery_lpm = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : Temp low recovery lpm is Empty\n", __func__);
|
|
|
|
pr_info("%s : HIGHLIMIT_THRESHOLD_NOLMAL(%d), HIGHLIMIT_RECOVERY_NORMAL(%d)\n"
|
|
"HIGH_THRESHOLD_NORMAL(%d), HIGH_RECOVERY_NORMAL(%d) LOW_THRESHOLD_NORMAL(%d), LOW_RECOVERY_NORMAL(%d)\n"
|
|
"HIGHLIMIT_THRESHOLD_LPM(%d), HIGHLIMIT_RECOVERY_LPM(%d)\n"
|
|
"HIGH_THRESHOLD_LPM(%d), HIGH_RECOVERY_LPM(%d) LOW_THRESHOLD_LPM(%d), LOW_RECOVERY_LPM(%d)\n",
|
|
__func__,
|
|
pdata->temp_highlimit_threshold_normal, pdata->temp_highlimit_recovery_normal,
|
|
pdata->temp_high_threshold_normal, pdata->temp_high_recovery_normal,
|
|
pdata->temp_low_threshold_normal, pdata->temp_low_recovery_normal,
|
|
pdata->temp_highlimit_threshold_lpm, pdata->temp_highlimit_recovery_lpm,
|
|
pdata->temp_high_threshold_lpm, pdata->temp_high_recovery_lpm,
|
|
pdata->temp_low_threshold_lpm, pdata->temp_low_recovery_lpm);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_high_threshold_normal",
|
|
&temp);
|
|
pdata->wpc_high_threshold_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : wpc_high_threshold_normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_high_recovery_normal",
|
|
&temp);
|
|
pdata->wpc_high_recovery_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : wpc_high_recovery_normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_low_threshold_normal",
|
|
&temp);
|
|
pdata->wpc_low_threshold_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : wpc_low_threshold_normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_low_recovery_normal",
|
|
&temp);
|
|
pdata->wpc_low_recovery_normal = (int)temp;
|
|
if (ret)
|
|
pr_info("%s : wpc_low_recovery_normal is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,full_check_type",
|
|
&pdata->full_check_type);
|
|
if (ret)
|
|
pr_info("%s : Full check type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,full_check_type_2nd",
|
|
&pdata->full_check_type_2nd);
|
|
if (ret)
|
|
pr_info("%s : Full check type 2nd is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,full_check_count",
|
|
&pdata->full_check_count);
|
|
if (ret)
|
|
pr_info("%s : Full check count is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_gpio_full_check",
|
|
&pdata->chg_gpio_full_check);
|
|
if (ret)
|
|
pr_info("%s : Chg gpio full check is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_polarity_full_check",
|
|
&pdata->chg_polarity_full_check);
|
|
if (ret)
|
|
pr_info("%s : Chg polarity full check is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,full_condition_type",
|
|
&pdata->full_condition_type);
|
|
if (ret)
|
|
pr_info("%s : Full condition type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,full_condition_soc",
|
|
&pdata->full_condition_soc);
|
|
if (ret)
|
|
pr_info("%s : Full condition soc is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,full_condition_vcell",
|
|
&pdata->full_condition_vcell);
|
|
if (ret)
|
|
pr_info("%s : Full condition vcell is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,recharge_check_count",
|
|
&pdata->recharge_check_count);
|
|
if (ret)
|
|
pr_info("%s : Recharge check count is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,recharge_condition_type",
|
|
&pdata->recharge_condition_type);
|
|
if (ret)
|
|
pr_info("%s : Recharge condition type is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,recharge_condition_soc",
|
|
&pdata->recharge_condition_soc);
|
|
if (ret)
|
|
pr_info("%s : Recharge condition soc is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,recharge_condition_vcell",
|
|
&pdata->recharge_condition_vcell);
|
|
if (ret)
|
|
pr_info("%s : Recharge condition vcell is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,charging_total_time",
|
|
(unsigned int *)&pdata->charging_total_time);
|
|
if (ret)
|
|
pr_info("%s : Charging total time is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,hv_charging_total_time",
|
|
(unsigned int *)&pdata->hv_charging_total_time);
|
|
if (ret) {
|
|
pdata->hv_charging_total_time = 3 * 60 * 60;
|
|
pr_info("%s : HV Charging total time is %d\n",
|
|
__func__, pdata->hv_charging_total_time);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,normal_charging_total_time",
|
|
(unsigned int *)&pdata->normal_charging_total_time);
|
|
if (ret) {
|
|
pdata->normal_charging_total_time = 5 * 60 * 60;
|
|
pr_info("%s : Normal(WC) Charging total time is %d\n",
|
|
__func__, pdata->normal_charging_total_time);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,usb_charging_total_time",
|
|
(unsigned int *)&pdata->usb_charging_total_time);
|
|
if (ret) {
|
|
pdata->usb_charging_total_time = 10 * 60 * 60;
|
|
pr_info("%s : USB Charging total time is %d\n",
|
|
__func__, pdata->usb_charging_total_time);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,recharging_total_time",
|
|
(unsigned int *)&pdata->recharging_total_time);
|
|
if (ret)
|
|
pr_info("%s : Recharging total time is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,charging_reset_time",
|
|
(unsigned int *)&pdata->charging_reset_time);
|
|
if (ret)
|
|
pr_info("%s : Charging reset time is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,charging_reset_time",
|
|
(unsigned int *)&pdata->charging_reset_time);
|
|
if (ret)
|
|
pr_info("%s : Charging reset time is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_float_voltage_conv",
|
|
&pdata->chg_float_voltage_conv);
|
|
if (ret) {
|
|
pr_info("%s: chg_float_voltage_conv is Empty\n", __func__);
|
|
pdata->chg_float_voltage_conv = 1;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,chg_float_voltage",
|
|
(unsigned int *)&pdata->chg_float_voltage);
|
|
if (ret) {
|
|
pr_info("%s: chg_float_voltage is Empty\n", __func__);
|
|
pdata->chg_float_voltage = 4350 * battery->pdata->chg_float_voltage_conv;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wa_volt_recov",
|
|
(unsigned int *)&pdata->wa_volt_recov);
|
|
if (ret) {
|
|
pdata->wa_volt_recov = 4090;
|
|
pr_info("%s: wa volt recov is Empty\n", __func__);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wa_volt_thr",
|
|
(unsigned int *)&pdata->wa_volt_thr);
|
|
if (ret) {
|
|
pdata->wa_volt_thr = 4100;
|
|
pr_info("%s: wa volt thr is Empty\n", __func__);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wa_float_voltage",
|
|
(unsigned int *)&pdata->wa_float_voltage);
|
|
if (ret) {
|
|
pdata->wa_float_voltage = 4050 * pdata->chg_float_voltage_conv;
|
|
pr_info("%s: wa float voltage is Empty\n", __func__);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,wa_fl_check_count",
|
|
&pdata->wa_fl_check_count);
|
|
if (ret) {
|
|
pdata->wa_fl_check_count = 3;
|
|
pr_info("%s : swelling fl check count is Empty\n", __func__);
|
|
}
|
|
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
ret = of_property_read_u32(np, "battery,chg_float_voltage",
|
|
(unsigned int *)&pdata->swelling_normal_float_voltage);
|
|
if (ret)
|
|
pr_info("%s: chg_float_voltage is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_high_temp_block",
|
|
&temp);
|
|
pdata->swelling_high_temp_block = (int)temp;
|
|
if (ret)
|
|
pr_info("%s: swelling high temp block is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_high_temp_recov",
|
|
&temp);
|
|
pdata->swelling_high_temp_recov = (int)temp;
|
|
if (ret)
|
|
pr_info("%s: swelling high temp recovery is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_wc_high_temp_recov",
|
|
&temp);
|
|
pdata->swelling_wc_high_temp_recov = (int)temp;
|
|
if (ret) {
|
|
pdata->swelling_wc_high_temp_recov = pdata->swelling_high_temp_recov;
|
|
pr_info("%s: swelling wireless high temp recovery is %d\n",
|
|
__func__, pdata->swelling_wc_high_temp_recov);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_temp_block_1st",
|
|
&temp);
|
|
pdata->swelling_low_temp_block_1st = (int)temp;
|
|
if (ret)
|
|
pr_info("%s: swelling low temp block is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_temp_recov_1st",
|
|
&temp);
|
|
pdata->swelling_low_temp_recov_1st = (int)temp;
|
|
if (ret)
|
|
pr_info("%s: swelling low temp recovery is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_temp_block_2nd",
|
|
&temp);
|
|
pdata->swelling_low_temp_block_2nd = (int)temp;
|
|
if (ret)
|
|
pr_info("%s: swelling low temp block is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_temp_recov_2nd",
|
|
&temp);
|
|
pdata->swelling_low_temp_recov_2nd = (int)temp;
|
|
if (ret)
|
|
pr_info("%s: swelling low temp recovery 2nd is Empty\n", __func__);
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_temp_current",
|
|
&pdata->swelling_low_temp_current);
|
|
if (ret) {
|
|
pr_info("%s: swelling_low_temp_current is Empty, Default value 600mA\n", __func__);
|
|
pdata->swelling_low_temp_current = 600;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_temp_current_2nd",
|
|
&pdata->swelling_low_temp_current_2nd);
|
|
if (ret) {
|
|
pr_info("%s: swelling_low_temp_current_2nd is Empty, Default value 600mA\n", __func__);
|
|
pdata->swelling_low_temp_current_2nd = pdata->swelling_low_temp_current;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_temp_topoff",
|
|
&pdata->swelling_low_temp_topoff);
|
|
if (ret) {
|
|
pr_info("%s: swelling_low_temp_topoff is Empty, Default value 200mA\n", __func__);
|
|
pdata->swelling_low_temp_topoff = 200;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_high_temp_current",
|
|
&pdata->swelling_high_temp_current);
|
|
if (ret) {
|
|
pr_info("%s: swelling_high_temp_current is Empty, Default value 1300mA\n", __func__);
|
|
pdata->swelling_high_temp_current = 1300;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_high_temp_topoff",
|
|
&pdata->swelling_high_temp_topoff);
|
|
if (ret) {
|
|
pr_info("%s: swelling_high_temp_topoff is Empty, Default value 200mA\n", __func__);
|
|
pdata->swelling_high_temp_topoff = 200;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_wc_high_temp_current",
|
|
&pdata->swelling_wc_high_temp_current);
|
|
if (ret) {
|
|
pr_info("%s: swelling_wc_high_temp_current is Empty, Default value 600mA\n", __func__);
|
|
pdata->swelling_wc_high_temp_current = 600;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_wc_low_temp_current",
|
|
&pdata->swelling_wc_low_temp_current);
|
|
if (ret) {
|
|
pr_info("%s: swelling_wc_low_temp_current is Empty, Default value 600mA\n", __func__);
|
|
pdata->swelling_wc_low_temp_current = 600;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_wc_low_temp_current_2nd",
|
|
&pdata->swelling_wc_low_temp_current_2nd);
|
|
if (ret) {
|
|
pr_info("%s: swelling_wc_low_temp_current_2nd is Empty, set swelling_wc_low_temp_current \n", __func__);
|
|
pdata->swelling_wc_low_temp_current_2nd = pdata->swelling_wc_low_temp_current;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_drop_float_voltage",
|
|
(unsigned int *)&pdata->swelling_drop_float_voltage);
|
|
if (ret) {
|
|
pr_info("%s: swelling drop float voltage is Empty, Default value 4250mV\n", __func__);
|
|
pdata->swelling_drop_float_voltage = 4250 * pdata->chg_float_voltage_conv;
|
|
pdata->swelling_drop_voltage_condition = 4250;
|
|
} else {
|
|
pdata->swelling_drop_voltage_condition =
|
|
pdata->swelling_drop_float_voltage / pdata->chg_float_voltage_conv;
|
|
pr_info("%s : swelling drop voltage(set : %d, condition : %d)\n", __func__,
|
|
pdata->swelling_drop_float_voltage, pdata->swelling_drop_voltage_condition);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_high_rechg_voltage",
|
|
(unsigned int *)&pdata->swelling_high_rechg_voltage);
|
|
if (ret) {
|
|
pr_info("%s: swelling_high_rechg_voltage is Empty\n", __func__);
|
|
pdata->swelling_high_rechg_voltage = 4150;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_rechg_voltage",
|
|
(unsigned int *)&pdata->swelling_low_rechg_voltage);
|
|
if (ret) {
|
|
pr_info("%s: swelling_low_rechg_voltage is Empty\n", __func__);
|
|
pdata->swelling_low_rechg_voltage = 4000;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,swelling_low_rechg_thr",
|
|
(unsigned int *)&pdata->swelling_low_rechg_thr);
|
|
if (ret) {
|
|
pr_info("%s: swelling_low_rechg_voltage_threshold is Empty\n", __func__);
|
|
pdata->swelling_low_rechg_thr = 150;
|
|
}
|
|
|
|
pr_info("%s : SWELLING_HIGH_TEMP(%d) SWELLING_HIGH_TEMP_RECOVERY(%d)\n"
|
|
"SWELLING_LOW_TEMP_1st(%d) SWELLING_LOW_TEMP_RECOVERY_1st(%d) "
|
|
"SWELLING_LOW_TEMP_2nd(%d) SWELLING_LOW_TEMP_RECOVERY_2nd(%d) "
|
|
"SWELLING_LOW_CURRENT(%d, %d), SWELLING_HIGH_CURRENT(%d, %d)\n"
|
|
"SWELLING_LOW_RCHG_VOL(%d), SWELLING_HIGH_RCHG_VOL(%d)\n"
|
|
"SWELLING_LOW_TEMP_RECHARGE_VOL_THRESHOLD(%d)\n",
|
|
__func__, pdata->swelling_high_temp_block, pdata->swelling_high_temp_recov,
|
|
pdata->swelling_low_temp_block_1st, pdata->swelling_low_temp_recov_1st,
|
|
pdata->swelling_low_temp_block_2nd, pdata->swelling_low_temp_recov_2nd,
|
|
pdata->swelling_low_temp_current, pdata->swelling_low_temp_topoff,
|
|
pdata->swelling_high_temp_current, pdata->swelling_high_temp_topoff,
|
|
pdata->swelling_low_rechg_voltage, pdata->swelling_high_rechg_voltage,
|
|
pdata->swelling_low_rechg_thr);
|
|
#endif
|
|
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
ret = of_property_read_u32(np, "battery,ttf_hv_12v_charge_current",
|
|
&pdata->ttf_hv_12v_charge_current);
|
|
if (ret) {
|
|
pdata->ttf_hv_12v_charge_current =
|
|
pdata->charging_current[SEC_BATTERY_CABLE_12V_TA].fast_charging_current;
|
|
pr_info("%s: ttf_hv_12v_charge_current is Empty, Default value %d\n",
|
|
__func__, pdata->ttf_hv_12v_charge_current);
|
|
}
|
|
ret = of_property_read_u32(np, "battery,ttf_hv_charge_current",
|
|
&pdata->ttf_hv_charge_current);
|
|
if (ret) {
|
|
pdata->ttf_hv_charge_current =
|
|
pdata->charging_current[SEC_BATTERY_CABLE_9V_TA].fast_charging_current;
|
|
pr_info("%s: ttf_hv_charge_current is Empty, Default value %d\n",
|
|
__func__, pdata->ttf_hv_charge_current);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,ttf_hv_wireless_charge_current",
|
|
&pdata->ttf_hv_wireless_charge_current);
|
|
if (ret) {
|
|
pr_info("%s: ttf_hv_wireless_charge_current is Empty, Default value 0\n", __func__);
|
|
pdata->ttf_hv_wireless_charge_current =
|
|
pdata->charging_current[SEC_BATTERY_CABLE_HV_WIRELESS].fast_charging_current - 300;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,ttf_wireless_charge_current",
|
|
&pdata->ttf_wireless_charge_current);
|
|
if (ret) {
|
|
pr_info("%s: ttf_wireless_charge_current is Empty, Default value 0\n", __func__);
|
|
pdata->ttf_wireless_charge_current =
|
|
pdata->charging_current[SEC_BATTERY_CABLE_WIRELESS].input_current_limit;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE)
|
|
/* wpc_det */
|
|
ret = pdata->wpc_det = of_get_named_gpio(np, "battery,wpc_det", 0);
|
|
if (ret < 0) {
|
|
pr_info("%s : can't get wpc_det\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
/* wpc_en */
|
|
ret = pdata->wpc_en = of_get_named_gpio(np, "battery,wpc_en", 0);
|
|
if (ret < 0) {
|
|
pr_info("%s : can't get wpc_en\n", __func__);
|
|
pdata->wpc_en = 0;
|
|
}
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
p = of_get_property(np, "battery,age_data", &len);
|
|
if (p) {
|
|
battery->pdata->num_age_step = len / sizeof(sec_age_data_t);
|
|
battery->pdata->age_data = kzalloc(len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,age_data",
|
|
(u32 *)battery->pdata->age_data, len/sizeof(u32));
|
|
if (ret) {
|
|
pr_err("%s: [Long life] failed to read battery->pdata->age_data: %d\n",
|
|
__func__, ret);
|
|
kfree(battery->pdata->age_data);
|
|
battery->pdata->age_data = NULL;
|
|
battery->pdata->num_age_step = 0;
|
|
}
|
|
#if defined(CONFIG_STEP_CHARGING)
|
|
for (len = 0; len < battery->pdata->num_age_step; ++len) {
|
|
pr_err("[%d/%d]cycle:%d, float:%d, full_v:%d, recharge_v:%d, soc:%d, step charging condition:%d\n",
|
|
len, battery->pdata->num_age_step-1,
|
|
battery->pdata->age_data[len].cycle,
|
|
battery->pdata->age_data[len].float_voltage,
|
|
battery->pdata->age_data[len].full_condition_vcell,
|
|
battery->pdata->age_data[len].recharge_condition_vcell,
|
|
battery->pdata->age_data[len].full_condition_soc,
|
|
battery->pdata->age_data[len].step_charging_condition);
|
|
}
|
|
#else
|
|
for (len = 0; len < battery->pdata->num_age_step; ++len) {
|
|
pr_err("[%d/%d]cycle:%d, float:%d, full_v:%d, recharge_v:%d, soc:%d\n",
|
|
len, battery->pdata->num_age_step-1,
|
|
battery->pdata->age_data[len].cycle,
|
|
battery->pdata->age_data[len].float_voltage,
|
|
battery->pdata->age_data[len].full_condition_vcell,
|
|
battery->pdata->age_data[len].recharge_condition_vcell,
|
|
battery->pdata->age_data[len].full_condition_soc);
|
|
}
|
|
#endif
|
|
} else {
|
|
battery->pdata->num_age_step = 0;
|
|
pr_err("%s: [Long life] there is not age_data\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
ret = of_property_read_u32(np, "battery,fg_cycle_check_value",
|
|
&pdata->fg_cycle_check_value);
|
|
if (ret) {
|
|
pr_err("%s: fg_cycle_check_value set default(1000)\n", __func__);
|
|
pdata->fg_cycle_check_value = 1000;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_default_power",
|
|
&pdata->siop_default_power);
|
|
if (ret) {
|
|
pr_err("%s: siop_default_power is Empty\n", __func__);
|
|
pdata->siop_default_power = 0;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_event_check_type",
|
|
&pdata->siop_event_check_type);
|
|
ret = of_property_read_u32(np, "battery,siop_call_cc_current",
|
|
&pdata->siop_call_cc_current);
|
|
ret = of_property_read_u32(np, "battery,siop_call_cv_current",
|
|
&pdata->siop_call_cv_current);
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_input_limit_current",
|
|
&pdata->siop_input_limit_current);
|
|
if (ret)
|
|
pdata->siop_input_limit_current = SIOP_INPUT_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_charging_limit_current",
|
|
&pdata->siop_charging_limit_current);
|
|
if (ret)
|
|
pdata->siop_charging_limit_current = SIOP_CHARGING_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_hv_12v_input_limit_current",
|
|
&pdata->siop_hv_12v_input_limit_current);
|
|
if (ret)
|
|
pdata->siop_hv_12v_input_limit_current = SIOP_HV_12V_INPUT_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_hv_12v_charging_limit_current",
|
|
&pdata->siop_hv_12v_charging_limit_current);
|
|
if (ret)
|
|
pdata->siop_hv_12v_charging_limit_current = SIOP_HV_12V_CHARGING_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_hv_input_limit_current",
|
|
&pdata->siop_hv_input_limit_current);
|
|
if (ret)
|
|
pdata->siop_hv_input_limit_current = SIOP_HV_INPUT_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_hv_charging_limit_current",
|
|
&pdata->siop_hv_charging_limit_current);
|
|
if (ret)
|
|
pdata->siop_hv_charging_limit_current = SIOP_HV_CHARGING_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_wireless_input_limit_current",
|
|
&pdata->siop_wireless_input_limit_current);
|
|
if (ret)
|
|
pdata->siop_wireless_input_limit_current = SIOP_WIRELESS_INPUT_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_wireless_charging_limit_current",
|
|
&pdata->siop_wireless_charging_limit_current);
|
|
if (ret)
|
|
pdata->siop_wireless_charging_limit_current = SIOP_WIRELESS_CHARGING_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_hv_wireless_input_limit_current",
|
|
&pdata->siop_hv_wireless_input_limit_current);
|
|
if (ret)
|
|
pdata->siop_hv_wireless_input_limit_current = SIOP_HV_WIRELESS_INPUT_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_hv_wireless_charging_limit_current",
|
|
&pdata->siop_hv_wireless_charging_limit_current);
|
|
if (ret)
|
|
pdata->siop_hv_wireless_charging_limit_current = SIOP_HV_WIRELESS_CHARGING_LIMIT_CURRENT;
|
|
|
|
ret = of_property_read_u32(np, "battery,minimum_charging_current_by_siop_0", &pdata->minimum_charging_current_by_siop_0);
|
|
if (ret) {
|
|
pr_info("%s : minimum_charging_current_by_siop_0 is Empty\n", __func__);
|
|
pdata->minimum_charging_current_by_siop_0 = 0;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,input_current_by_siop_20", &pdata->input_current_by_siop_20);
|
|
if (ret) {
|
|
pr_info("%s : input_current_by_siop_20 is Empty\n", __func__);
|
|
pdata->input_current_by_siop_20 = 0;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,input_current_by_siop_40", &pdata->input_current_by_siop_40);
|
|
if (ret) {
|
|
pr_info("%s : input_current_by_siop_40 is Empty\n", __func__);
|
|
pdata->input_current_by_siop_40 = 0;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,charging_current_browsing_mode", &pdata->charging_current_browsing_mode);
|
|
if (ret) {
|
|
pr_info("%s : charging_current_browsing_mode is Empty\n", __func__);
|
|
pdata->charging_current_browsing_mode = 0;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,max_input_voltage",
|
|
&pdata->max_input_voltage);
|
|
if (ret)
|
|
pdata->max_input_voltage = 12000;
|
|
|
|
ret = of_property_read_u32(np, "battery,max_input_current",
|
|
&pdata->max_input_current);
|
|
if (ret)
|
|
pdata->max_input_current = 3000;
|
|
|
|
ret = of_property_read_u32(np, "battery,pd_charging_charge_power",
|
|
&pdata->pd_charging_charge_power);
|
|
if (ret) {
|
|
pr_err("%s: pd_charging_charge_power is Empty\n", __func__);
|
|
pdata->pd_charging_charge_power = 15000;
|
|
}
|
|
|
|
pr_info("%s: vendor : %s, technology : %d, cable_check_type : %d\n"
|
|
"cable_source_type : %d, event_waiting_time : %d\n"
|
|
"polling_type : %d, initial_count : %d, check_count : %d\n"
|
|
"check_adc_max : %d, check_adc_min : %d\n"
|
|
"ovp_uvlo_check_type : %d, thermal_source : %d, chg_thermal_source : %d\n"
|
|
"temp_check_type : %d, temp_check_count : %d\n"
|
|
"chg_heating_prevention_method : %d\n",
|
|
__func__,
|
|
pdata->vendor, pdata->technology,pdata->cable_check_type,
|
|
pdata->cable_source_type, pdata->event_waiting_time,
|
|
pdata->polling_type, pdata->monitor_initial_count,
|
|
pdata->check_count, pdata->check_adc_max, pdata->check_adc_min,
|
|
pdata->ovp_uvlo_check_type, pdata->thermal_source, pdata->chg_thermal_source,
|
|
pdata->temp_check_type, pdata->temp_check_count,
|
|
pdata->chg_heating_prevention_method);
|
|
|
|
ret = of_property_read_u32(np, "battery,prepare_afc_delay",
|
|
&battery->prepare_afc_delay);
|
|
if (ret)
|
|
battery->prepare_afc_delay = 500;
|
|
|
|
#if defined(CONFIG_STEP_CHARGING)
|
|
sec_step_charging_init(battery, dev);
|
|
#endif
|
|
ret = of_property_read_u32(np, "battery,base_charge_power",
|
|
&battery->base_charge_power);
|
|
if (ret)
|
|
battery->base_charge_power = 10000;
|
|
|
|
ret = of_property_read_u32(np, "battery,max_charging_current",
|
|
&pdata->max_charging_current);
|
|
if (ret) {
|
|
pr_err("%s: max_charging_current is Empty\n", __func__);
|
|
pdata->max_charging_current = 3000;
|
|
}
|
|
|
|
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
p = of_get_property(np, "battery,ignore_cisd_index", &len);
|
|
pdata->ignore_cisd_index = kzalloc(sizeof(*pdata->ignore_cisd_index) * 2, GFP_KERNEL);
|
|
if (p) {
|
|
len = len / sizeof(u32);
|
|
ret = of_property_read_u32_array(np, "battery,ignore_cisd_index",
|
|
pdata->ignore_cisd_index, len);
|
|
} else {
|
|
pr_info("%s : battery,ignore_cisd_index is Empty\n", __func__);
|
|
}
|
|
|
|
p = of_get_property(np, "battery,ignore_cisd_index_d", &len);
|
|
pdata->ignore_cisd_index_d = kzalloc(sizeof(*pdata->ignore_cisd_index_d) * 2, GFP_KERNEL);
|
|
if (p) {
|
|
len = len / sizeof(u32);
|
|
ret = of_property_read_u32_array(np, "battery,ignore_cisd_index_d",
|
|
pdata->ignore_cisd_index_d, len);
|
|
} else {
|
|
pr_info("%s : battery,ignore_cisd_index_d is Empty\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
pdata->recovery_cable = of_property_read_bool(np,
|
|
"battery,recovery_cable");
|
|
|
|
pdata->lowtemp_support_full_volt = of_property_read_bool(np,
|
|
"battery,lowtemp_support_full_volt");
|
|
return 0;
|
|
}
|
|
|
|
static void sec_bat_parse_mode_dt(struct sec_battery_info *battery)
|
|
{
|
|
struct device_node *np;
|
|
sec_battery_platform_data_t *pdata = battery->pdata;
|
|
int ret = 0;
|
|
u32 temp = 0;
|
|
|
|
np = of_find_node_by_name(NULL, "battery");
|
|
if (!np) {
|
|
pr_err("%s np NULL\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (battery->store_mode) {
|
|
ret = of_property_read_u32(np, "battery,store_mode_afc_input_current",
|
|
&pdata->store_mode_afc_input_current);
|
|
if (ret) {
|
|
pr_info("%s : store_mode_afc_input_current is Empty\n", __func__);
|
|
pdata->store_mode_afc_input_current = 440;
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,store_mode_hv_wireless_input_current",
|
|
&pdata->store_mode_hv_wireless_input_current);
|
|
if (ret) {
|
|
pr_info("%s : store_mode_hv_wireless_input_current is Empty\n", __func__);
|
|
pdata->store_mode_hv_wireless_input_current = 400;
|
|
}
|
|
|
|
if (pdata->wpc_temp_check) {
|
|
ret = of_property_read_u32(np, "battery,wpc_store_high_temp",
|
|
&temp);
|
|
if (!ret)
|
|
pdata->wpc_high_temp = temp;
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_store_high_temp_recovery",
|
|
&temp);
|
|
if (!ret)
|
|
pdata->wpc_high_temp_recovery = temp;
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_store_charging_limit_current",
|
|
&temp);
|
|
if (!ret)
|
|
pdata->wpc_charging_limit_current = temp;
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_store_lcd_on_high_temp",
|
|
&temp);
|
|
if (!ret)
|
|
pdata->wpc_lcd_on_high_temp = (int)temp;
|
|
|
|
ret = of_property_read_u32(np, "battery,wpc_store_lcd_on_high_temp_rec",
|
|
&temp);
|
|
if (!ret)
|
|
pdata->wpc_lcd_on_high_temp_rec = (int)temp;
|
|
|
|
pr_info("%s: update store_mode - wpc high_temp(t:%d, r:%d), lcd_on_high_temp(t:%d, r:%d), curr(%d)\n",
|
|
__func__,
|
|
pdata->wpc_high_temp, pdata->wpc_high_temp_recovery,
|
|
pdata->wpc_lcd_on_high_temp, pdata->wpc_lcd_on_high_temp_rec,
|
|
pdata->wpc_charging_limit_current);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,siop_store_hv_wireless_input_limit_current",
|
|
&temp);
|
|
if (!ret)
|
|
pdata->siop_hv_wireless_input_limit_current = temp;
|
|
else
|
|
pdata->siop_hv_wireless_input_limit_current = SIOP_STORE_HV_WIRELESS_CHARGING_LIMIT_CURRENT;
|
|
pr_info("%s: update siop_hv_wireless_input_limit_current(%d)\n",
|
|
__func__, pdata->siop_hv_wireless_input_limit_current);
|
|
}
|
|
}
|
|
|
|
static void sec_bat_parse_mode_dt_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, parse_mode_dt_work.work);
|
|
|
|
sec_bat_parse_mode_dt(battery);
|
|
|
|
if (is_hv_wire_type(battery->cable_type) ||
|
|
is_hv_wireless_type(battery->cable_type)) {
|
|
sec_bat_set_charging_current(battery);
|
|
}
|
|
|
|
wake_unlock(&battery->parse_mode_dt_wake_lock);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_OF
|
|
extern sec_battery_platform_data_t sec_battery_pdata;
|
|
#endif
|
|
|
|
#if !defined(CONFIG_MUIC_NOTIFIER)
|
|
static void cable_initial_check(struct sec_battery_info *battery)
|
|
{
|
|
union power_supply_propval value;
|
|
|
|
pr_info("%s : current_cable_type : (%d)\n", __func__, battery->cable_type);
|
|
|
|
if (SEC_BATTERY_CABLE_NONE != battery->cable_type) {
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_POWER_SHARING) {
|
|
value.intval = battery->cable_type;
|
|
psy_do_property("ps", set,
|
|
POWER_SUPPLY_PROP_ONLINE, value);
|
|
} else {
|
|
value.intval = battery->cable_type;
|
|
psy_do_property("battery", set,
|
|
POWER_SUPPLY_PROP_ONLINE, value);
|
|
}
|
|
} else {
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_PROP_ONLINE, value);
|
|
if (value.intval == SEC_BATTERY_CABLE_WIRELESS) {
|
|
value.intval = 1;
|
|
psy_do_property("wireless", set,
|
|
POWER_SUPPLY_PROP_ONLINE, value);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void sec_bat_init_chg_work(struct work_struct *work)
|
|
{
|
|
struct sec_battery_info *battery = container_of(work,
|
|
struct sec_battery_info, init_chg_work.work);
|
|
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_NONE &&
|
|
!(battery->misc_event & (BATT_MISC_EVENT_UNDEFINED_RANGE_TYPE |
|
|
BATT_MISC_EVENT_HICCUP_TYPE))) {
|
|
pr_info("%s: disable charging\n", __func__);
|
|
sec_bat_set_charge(battery, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
}
|
|
}
|
|
|
|
static const struct power_supply_desc battery_power_supply_desc = {
|
|
.name = "battery",
|
|
.type = POWER_SUPPLY_TYPE_BATTERY,
|
|
.properties = sec_battery_props,
|
|
.num_properties = ARRAY_SIZE(sec_battery_props),
|
|
.get_property = sec_bat_get_property,
|
|
.set_property = sec_bat_set_property,
|
|
};
|
|
|
|
static const struct power_supply_desc usb_power_supply_desc = {
|
|
.name = "usb",
|
|
.type = POWER_SUPPLY_TYPE_USB,
|
|
.properties = sec_power_props,
|
|
.num_properties = ARRAY_SIZE(sec_power_props),
|
|
.get_property = sec_usb_get_property,
|
|
};
|
|
|
|
static const struct power_supply_desc ac_power_supply_desc = {
|
|
.name = "ac",
|
|
.type = POWER_SUPPLY_TYPE_MAINS,
|
|
.properties = sec_ac_props,
|
|
.num_properties = ARRAY_SIZE(sec_ac_props),
|
|
.get_property = sec_ac_get_property,
|
|
};
|
|
|
|
static const struct power_supply_desc wireless_power_supply_desc = {
|
|
.name = "wireless",
|
|
.type = POWER_SUPPLY_TYPE_WIRELESS,
|
|
.properties = sec_wireless_props,
|
|
.num_properties = ARRAY_SIZE(sec_wireless_props),
|
|
.get_property = sec_wireless_get_property,
|
|
.set_property = sec_wireless_set_property,
|
|
};
|
|
|
|
static const struct power_supply_desc ps_power_supply_desc = {
|
|
.name = "ps",
|
|
.type = POWER_SUPPLY_TYPE_POWER_SHARING,
|
|
.properties = sec_ps_props,
|
|
.num_properties = ARRAY_SIZE(sec_ps_props),
|
|
.get_property = sec_ps_get_property,
|
|
.set_property = sec_ps_set_property,
|
|
};
|
|
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
extern bool sales_code_is(char* str);
|
|
#endif
|
|
static int sec_battery_probe(struct platform_device *pdev)
|
|
{
|
|
sec_battery_platform_data_t *pdata = NULL;
|
|
struct sec_battery_info *battery;
|
|
struct power_supply_config battery_cfg = {};
|
|
|
|
int ret = 0;
|
|
#ifndef CONFIG_OF
|
|
int i = 0;
|
|
#endif
|
|
|
|
union power_supply_propval value = {0, };
|
|
|
|
dev_info(&pdev->dev,
|
|
"%s: SEC Battery Driver Loading\n", __func__);
|
|
|
|
battery = kzalloc(sizeof(*battery), GFP_KERNEL);
|
|
if (!battery)
|
|
return -ENOMEM;
|
|
|
|
if (pdev->dev.of_node) {
|
|
pdata = devm_kzalloc(&pdev->dev,
|
|
sizeof(sec_battery_platform_data_t),
|
|
GFP_KERNEL);
|
|
if (!pdata) {
|
|
dev_err(&pdev->dev, "Failed to allocate memory\n");
|
|
ret = -ENOMEM;
|
|
goto err_bat_free;
|
|
}
|
|
|
|
battery->pdata = pdata;
|
|
|
|
if (sec_bat_parse_dt(&pdev->dev, battery)) {
|
|
dev_err(&pdev->dev,
|
|
"%s: Failed to get battery dt\n", __func__);
|
|
ret = -EINVAL;
|
|
goto err_bat_free;
|
|
}
|
|
} else {
|
|
pdata = dev_get_platdata(&pdev->dev);
|
|
battery->pdata = pdata;
|
|
}
|
|
|
|
platform_set_drvdata(pdev, battery);
|
|
|
|
battery->dev = &pdev->dev;
|
|
|
|
mutex_init(&battery->adclock);
|
|
mutex_init(&battery->iolock);
|
|
mutex_init(&battery->misclock);
|
|
mutex_init(&battery->batt_handlelock);
|
|
mutex_init(&battery->current_eventlock);
|
|
mutex_init(&battery->typec_notylock);
|
|
|
|
dev_dbg(battery->dev, "%s: ADC init\n", __func__);
|
|
|
|
#ifdef CONFIG_OF
|
|
adc_init(pdev, battery);
|
|
#else
|
|
for (i = 0; i < SEC_BAT_ADC_CHANNEL_NUM; i++)
|
|
adc_init(pdev, pdata, i);
|
|
#endif
|
|
wake_lock_init(&battery->monitor_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-monitor");
|
|
wake_lock_init(&battery->cable_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-cable");
|
|
wake_lock_init(&battery->vbus_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-vbus");
|
|
wake_lock_init(&battery->afc_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-afc");
|
|
wake_lock_init(&battery->siop_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-siop");
|
|
wake_lock_init(&battery->siop_level_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-siop_level");
|
|
wake_lock_init(&battery->siop_event_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-siop_event");
|
|
wake_lock_init(&battery->wc_headroom_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-wc_headroom");
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
wake_lock_init(&battery->batt_data_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-update-data");
|
|
#endif
|
|
wake_lock_init(&battery->misc_event_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-misc-event");
|
|
#ifdef CONFIG_OF
|
|
wake_lock_init(&battery->parse_mode_dt_wake_lock, WAKE_LOCK_SUSPEND,
|
|
"sec-battery-parse_mode_dt");
|
|
#endif
|
|
|
|
/* initialization of battery info */
|
|
sec_bat_set_charging_status(battery,
|
|
POWER_SUPPLY_STATUS_DISCHARGING);
|
|
battery->health = POWER_SUPPLY_HEALTH_GOOD;
|
|
battery->present = true;
|
|
battery->is_jig_on = false;
|
|
battery->wdt_kick_disable = 0;
|
|
|
|
battery->polling_count = 1; /* initial value = 1 */
|
|
battery->polling_time = pdata->polling_time[
|
|
SEC_BATTERY_POLLING_TIME_DISCHARGING];
|
|
battery->polling_in_sleep = false;
|
|
battery->polling_short = false;
|
|
|
|
battery->check_count = 0;
|
|
battery->check_adc_count = 0;
|
|
battery->check_adc_value = 0;
|
|
|
|
battery->input_current = 0;
|
|
battery->charging_current = 0;
|
|
battery->topoff_current = 0;
|
|
battery->wpc_vout_level = WIRELESS_VOUT_10V;
|
|
battery->charging_start_time = 0;
|
|
battery->charging_passed_time = 0;
|
|
battery->wc_heating_start_time = 0;
|
|
battery->wc_heating_passed_time = 0;
|
|
battery->charging_next_time = 0;
|
|
battery->charging_fullcharged_time = 0;
|
|
battery->siop_level = 100;
|
|
battery->siop_event = 0;
|
|
battery->wc_enable = 1;
|
|
battery->wc_enable_cnt = 0;
|
|
battery->wc_enable_cnt_value = 3;
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
battery->stability_test = 0;
|
|
battery->eng_not_full_status = 0;
|
|
battery->temperature_test_battery = 0x7FFF;
|
|
battery->temperature_test_usb = 0x7FFF;
|
|
battery->temperature_test_wpc = 0x7FFF;
|
|
battery->temperature_test_chg = 0x7FFF;
|
|
#endif
|
|
battery->ps_enable = false;
|
|
battery->wc_status = SEC_WIRELESS_PAD_NONE;
|
|
battery->wc_cv_mode = false;
|
|
battery->wire_status = SEC_BATTERY_CABLE_NONE;
|
|
|
|
#if defined(CONFIG_BATTERY_SWELLING)
|
|
battery->swelling_mode = SWELLING_MODE_NONE;
|
|
#endif
|
|
battery->charging_block = true;
|
|
battery->chg_limit = false;
|
|
battery->mix_limit = false;
|
|
battery->usb_temp = 0;
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT) || defined(CONFIG_SEC_FACTORY)
|
|
battery->cooldown_mode = true;
|
|
#endif
|
|
battery->skip_swelling = false;
|
|
battery->led_cover = 0;
|
|
battery->wa_float_cnt = 0;
|
|
battery->hiccup_status = 0;
|
|
|
|
#if defined(CONFIG_ABNORMAL_BAT_THM_WA)
|
|
battery->temp_control = false;
|
|
battery->prev_bat_temp = 0x7FFF;
|
|
#endif
|
|
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_USB_100MA, SEC_BAT_CURRENT_EVENT_USB_100MA);
|
|
|
|
if (lpcharge) {
|
|
battery->temp_highlimit_threshold =
|
|
battery->pdata->temp_highlimit_threshold_lpm;
|
|
battery->temp_highlimit_recovery =
|
|
battery->pdata->temp_highlimit_recovery_lpm;
|
|
battery->temp_high_threshold =
|
|
battery->pdata->temp_high_threshold_lpm;
|
|
battery->temp_high_recovery =
|
|
battery->pdata->temp_high_recovery_lpm;
|
|
battery->temp_low_recovery =
|
|
battery->pdata->temp_low_recovery_lpm;
|
|
battery->temp_low_threshold =
|
|
battery->pdata->temp_low_threshold_lpm;
|
|
} else {
|
|
battery->temp_highlimit_threshold =
|
|
battery->pdata->temp_highlimit_threshold_normal;
|
|
battery->temp_highlimit_recovery =
|
|
battery->pdata->temp_highlimit_recovery_normal;
|
|
battery->temp_high_threshold =
|
|
battery->pdata->temp_high_threshold_normal;
|
|
battery->temp_high_recovery =
|
|
battery->pdata->temp_high_recovery_normal;
|
|
battery->temp_low_recovery =
|
|
battery->pdata->temp_low_recovery_normal;
|
|
battery->temp_low_threshold =
|
|
battery->pdata->temp_low_threshold_normal;
|
|
}
|
|
|
|
battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
|
|
battery->is_recharging = false;
|
|
battery->cable_type = SEC_BATTERY_CABLE_NONE;
|
|
battery->test_mode = 0;
|
|
battery->factory_mode = false;
|
|
battery->store_mode = false;
|
|
battery->slate_mode = false;
|
|
battery->usb_suspend_mode = false;
|
|
battery->is_hc_usb = false;
|
|
battery->is_sysovlo = false;
|
|
battery->is_vbatovlo = false;
|
|
battery->is_abnormal_temp = false;
|
|
|
|
battery->safety_timer_set = true;
|
|
battery->stop_timer = false;
|
|
battery->prev_safety_time = 0;
|
|
battery->lcd_status = false;
|
|
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
battery->usb_overheat_check = false;
|
|
battery->skip_cisd = false;
|
|
#endif
|
|
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
battery->batt_cycle = -1;
|
|
battery->pdata->age_step = 0;
|
|
#endif
|
|
|
|
battery->health_change = false;
|
|
#if 0
|
|
if (charging_night_mode == 49)
|
|
sleep_mode = true;
|
|
else
|
|
sleep_mode = false;
|
|
#endif
|
|
|
|
/* Check High Voltage charging option for wired charging */
|
|
if (get_afc_mode() == CH_MODE_AFC_DISABLE_VAL) {
|
|
pr_info("HV wired charging mode is disabled\n");
|
|
sec_bat_set_current_event(battery,
|
|
SEC_BAT_CURRENT_EVENT_HV_DISABLE, SEC_BAT_CURRENT_EVENT_HV_DISABLE);
|
|
}
|
|
|
|
battery->pdata->store_mode_charging_max = STORE_MODE_CHARGING_MAX;
|
|
battery->pdata->store_mode_charging_min = STORE_MODE_CHARGING_MIN;
|
|
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
if (sales_code_is("VZW")) {
|
|
dev_err(battery->dev, "%s: Sales is VZW\n", __func__);
|
|
battery->pdata->store_mode_charging_max = STORE_MODE_CHARGING_MAX_VZW;
|
|
battery->pdata->store_mode_charging_min = STORE_MODE_CHARGING_MIN_VZW;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
battery->timetofull = -1;
|
|
#endif
|
|
|
|
#if !defined(CONFIG_ENG_BATTERY_CONCEPT) && !defined(CONFIG_SEC_FACTORY)
|
|
if (battery->pdata->detect_moisture)
|
|
battery->block_water_event = !(get_switch_sel() & SWITCH_SEL_RUSTPROOF_MASK) ? 0 : 1;
|
|
else
|
|
battery->block_water_event = (battery->pdata->enable_water_resistance) ? 0 : 1;
|
|
pr_info("%s: init block_water_event = %d\n", __func__, battery->block_water_event);
|
|
#endif
|
|
|
|
if (battery->pdata->charger_name == NULL)
|
|
battery->pdata->charger_name = "sec-charger";
|
|
if (battery->pdata->fuelgauge_name == NULL)
|
|
battery->pdata->fuelgauge_name = "sec-fuelgauge";
|
|
|
|
/* create work queue */
|
|
battery->monitor_wqueue =
|
|
create_singlethread_workqueue(dev_name(&pdev->dev));
|
|
if (!battery->monitor_wqueue) {
|
|
dev_err(battery->dev,
|
|
"%s: Fail to Create Workqueue\n", __func__);
|
|
goto err_irq;
|
|
}
|
|
|
|
INIT_DELAYED_WORK(&battery->monitor_work, sec_bat_monitor_work);
|
|
INIT_DELAYED_WORK(&battery->cable_work, sec_bat_cable_work);
|
|
#if defined(CONFIG_CALC_TIME_TO_FULL)
|
|
INIT_DELAYED_WORK(&battery->timetofull_work, sec_bat_time_to_full_work);
|
|
#endif
|
|
INIT_DELAYED_WORK(&battery->slowcharging_work, sec_bat_check_slowcharging_work);
|
|
INIT_DELAYED_WORK(&battery->afc_work, sec_bat_afc_work);
|
|
INIT_DELAYED_WORK(&battery->siop_work, sec_bat_siop_work);
|
|
INIT_DELAYED_WORK(&battery->siop_event_work, sec_bat_siop_event_work);
|
|
INIT_DELAYED_WORK(&battery->siop_level_work, sec_bat_siop_level_work);
|
|
INIT_DELAYED_WORK(&battery->wc_headroom_work, sec_bat_wc_headroom_work);
|
|
#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE)
|
|
INIT_DELAYED_WORK(&battery->fw_init_work, sec_bat_fw_init_work);
|
|
#endif
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
INIT_DELAYED_WORK(&battery->batt_data_work, sec_bat_update_data_work);
|
|
#endif
|
|
INIT_DELAYED_WORK(&battery->misc_event_work, sec_bat_misc_event_work);
|
|
#ifdef CONFIG_OF
|
|
INIT_DELAYED_WORK(&battery->parse_mode_dt_work, sec_bat_parse_mode_dt_work);
|
|
#endif
|
|
INIT_DELAYED_WORK(&battery->init_chg_work, sec_bat_init_chg_work);
|
|
|
|
switch (pdata->polling_type) {
|
|
case SEC_BATTERY_MONITOR_WORKQUEUE:
|
|
INIT_DELAYED_WORK(&battery->polling_work,
|
|
sec_bat_polling_work);
|
|
break;
|
|
case SEC_BATTERY_MONITOR_ALARM:
|
|
battery->last_poll_time = ktime_get_boottime();
|
|
alarm_init(&battery->polling_alarm, ALARM_BOOTTIME,
|
|
sec_bat_alarm);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#if defined(CONFIG_BATTERY_CISD)
|
|
sec_battery_cisd_init(battery);
|
|
#endif
|
|
|
|
battery_cfg.drv_data = battery;
|
|
|
|
/* init power supplier framework */
|
|
battery->psy_ps = power_supply_register(&pdev->dev, &ps_power_supply_desc, &battery_cfg);
|
|
if (!battery->psy_ps) {
|
|
dev_err(battery->dev,
|
|
"%s: Failed to Register psy_ps\n", __func__);
|
|
goto err_workqueue;
|
|
}
|
|
battery->psy_ps->supplied_to = supply_list;
|
|
battery->psy_ps->num_supplicants = ARRAY_SIZE(supply_list);
|
|
|
|
battery->psy_wireless = power_supply_register(&pdev->dev, &wireless_power_supply_desc, &battery_cfg);
|
|
if (!battery->psy_wireless) {
|
|
dev_err(battery->dev,
|
|
"%s: Failed to Register psy_wireless\n", __func__);
|
|
goto err_supply_unreg_ps;
|
|
}
|
|
battery->psy_wireless->supplied_to = supply_list;
|
|
battery->psy_wireless->num_supplicants = ARRAY_SIZE(supply_list);
|
|
|
|
battery->psy_usb = power_supply_register(&pdev->dev, &usb_power_supply_desc, &battery_cfg);
|
|
if (!battery->psy_usb) {
|
|
dev_err(battery->dev,
|
|
"%s: Failed to Register psy_usb\n", __func__);
|
|
goto err_supply_unreg_wireless;
|
|
}
|
|
battery->psy_usb->supplied_to = supply_list;
|
|
battery->psy_usb->num_supplicants = ARRAY_SIZE(supply_list);
|
|
|
|
battery->psy_ac = power_supply_register(&pdev->dev, &ac_power_supply_desc, &battery_cfg);
|
|
if (!battery->psy_ac) {
|
|
dev_err(battery->dev,
|
|
"%s: Failed to Register psy_ac\n", __func__);
|
|
goto err_supply_unreg_usb;
|
|
}
|
|
battery->psy_ac->supplied_to = supply_list;
|
|
battery->psy_ac->num_supplicants = ARRAY_SIZE(supply_list);
|
|
|
|
battery->psy_bat = power_supply_register(&pdev->dev, &battery_power_supply_desc, &battery_cfg);
|
|
if (!battery->psy_bat) {
|
|
dev_err(battery->dev,
|
|
"%s: Failed to Register psy_bat\n", __func__);
|
|
goto err_supply_unreg_ac;
|
|
}
|
|
|
|
ret = sec_bat_create_attrs(&battery->psy_bat->dev);
|
|
if (ret) {
|
|
dev_err(battery->dev,
|
|
"%s : Failed to create_attrs\n", __func__);
|
|
goto err_req_irq;
|
|
}
|
|
|
|
battery->temperature = 0;
|
|
|
|
/* initialize battery level*/
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->fuelgauge_name, get,
|
|
POWER_SUPPLY_PROP_CAPACITY, value);
|
|
battery->capacity = value.intval;
|
|
|
|
#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE)
|
|
/* queue_delayed_work(battery->monitor_wqueue, &battery->fw_init_work, 0); */
|
|
#endif
|
|
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_TYPE, value);
|
|
|
|
#if defined(CONFIG_STORE_MODE) && !defined(CONFIG_SEC_FACTORY)
|
|
battery->store_mode = true;
|
|
sec_bat_parse_mode_dt(battery);
|
|
#endif
|
|
|
|
#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
|
|
battery->pdic_info.sink_status.rp_currentlvl = RP_CURRENT_LEVEL_NONE;
|
|
manager_notifier_register(&battery->usb_typec_nb,
|
|
usb_typec_handle_notification, MANAGER_NOTIFY_CCIC_BATTERY);
|
|
#else
|
|
#if defined(CONFIG_MUIC_NOTIFIER)
|
|
muic_notifier_register(&battery->batt_nb,
|
|
batt_handle_notification, MUIC_NOTIFY_DEV_CHARGER);
|
|
#else
|
|
cable_initial_check(battery);
|
|
#endif
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
pr_info("%s: Registering PDIC_NOTIFY.\n", __func__);
|
|
pdic_notifier_register(&battery->pdic_nb,
|
|
batt_pdic_handle_notification, PDIC_NOTIFY_DEV_BATTERY);
|
|
#endif
|
|
#endif
|
|
#if defined(CONFIG_VBUS_NOTIFIER)
|
|
vbus_notifier_register(&battery->vbus_nb,
|
|
vbus_handle_notification, VBUS_NOTIFY_DEV_CHARGER);
|
|
#endif
|
|
|
|
value.intval = true;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, value);
|
|
|
|
if ((battery->cable_type == SEC_BATTERY_CABLE_NONE) ||
|
|
(battery->cable_type == SEC_BATTERY_CABLE_PREPARE_TA)) {
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->init_chg_work, 0);
|
|
|
|
dev_info(&pdev->dev,
|
|
"%s: SEC Battery Driver Monitorwork\n", __func__);
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
|
|
}
|
|
|
|
if (battery->pdata->check_battery_callback)
|
|
battery->present = battery->pdata->check_battery_callback();
|
|
|
|
dev_info(battery->dev,
|
|
"%s: SEC Battery Driver Loaded\n", __func__);
|
|
return 0;
|
|
|
|
err_req_irq:
|
|
if (battery->pdata->bat_irq)
|
|
free_irq(battery->pdata->bat_irq, battery);
|
|
power_supply_unregister(battery->psy_bat);
|
|
err_supply_unreg_ac:
|
|
power_supply_unregister(battery->psy_ac);
|
|
err_supply_unreg_usb:
|
|
power_supply_unregister(battery->psy_usb);
|
|
err_supply_unreg_wireless:
|
|
power_supply_unregister(battery->psy_wireless);
|
|
err_supply_unreg_ps:
|
|
power_supply_unregister(battery->psy_ps);
|
|
err_workqueue:
|
|
destroy_workqueue(battery->monitor_wqueue);
|
|
err_irq:
|
|
wake_lock_destroy(&battery->monitor_wake_lock);
|
|
wake_lock_destroy(&battery->cable_wake_lock);
|
|
wake_lock_destroy(&battery->vbus_wake_lock);
|
|
wake_lock_destroy(&battery->afc_wake_lock);
|
|
wake_lock_destroy(&battery->siop_wake_lock);
|
|
wake_lock_destroy(&battery->siop_level_wake_lock);
|
|
wake_lock_destroy(&battery->siop_event_wake_lock);
|
|
wake_lock_destroy(&battery->wc_headroom_wake_lock);
|
|
#if defined(CONFIG_UPDATE_BATTERY_DATA)
|
|
wake_lock_destroy(&battery->batt_data_wake_lock);
|
|
#endif
|
|
wake_lock_destroy(&battery->misc_event_wake_lock);
|
|
#ifdef CONFIG_OF
|
|
wake_lock_destroy(&battery->parse_mode_dt_wake_lock);
|
|
#endif
|
|
mutex_destroy(&battery->adclock);
|
|
mutex_destroy(&battery->iolock);
|
|
mutex_destroy(&battery->misclock);
|
|
mutex_destroy(&battery->batt_handlelock);
|
|
mutex_destroy(&battery->current_eventlock);
|
|
mutex_destroy(&battery->typec_notylock);
|
|
kfree(pdata);
|
|
err_bat_free:
|
|
kfree(battery);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int sec_battery_remove(struct platform_device *pdev)
|
|
{
|
|
struct sec_battery_info *battery = platform_get_drvdata(pdev);
|
|
#ifndef CONFIG_OF
|
|
int i;
|
|
#endif
|
|
|
|
dev_dbg(battery->dev, "%s: Start\n", __func__);
|
|
|
|
switch (battery->pdata->polling_type) {
|
|
case SEC_BATTERY_MONITOR_WORKQUEUE:
|
|
cancel_delayed_work(&battery->polling_work);
|
|
break;
|
|
case SEC_BATTERY_MONITOR_ALARM:
|
|
alarm_cancel(&battery->polling_alarm);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
flush_workqueue(battery->monitor_wqueue);
|
|
destroy_workqueue(battery->monitor_wqueue);
|
|
wake_lock_destroy(&battery->monitor_wake_lock);
|
|
wake_lock_destroy(&battery->cable_wake_lock);
|
|
wake_lock_destroy(&battery->vbus_wake_lock);
|
|
wake_lock_destroy(&battery->afc_wake_lock);
|
|
wake_lock_destroy(&battery->siop_wake_lock);
|
|
wake_lock_destroy(&battery->siop_level_wake_lock);
|
|
wake_lock_destroy(&battery->siop_event_wake_lock);
|
|
wake_lock_destroy(&battery->misc_event_wake_lock);
|
|
mutex_destroy(&battery->adclock);
|
|
mutex_destroy(&battery->iolock);
|
|
mutex_destroy(&battery->misclock);
|
|
mutex_destroy(&battery->batt_handlelock);
|
|
mutex_destroy(&battery->current_eventlock);
|
|
mutex_destroy(&battery->typec_notylock);
|
|
|
|
#ifdef CONFIG_OF
|
|
adc_exit(battery);
|
|
#else
|
|
for (i = 0; i < SEC_BAT_ADC_CHANNEL_NUM; i++)
|
|
adc_exit(battery->pdata, i);
|
|
#endif
|
|
power_supply_unregister(battery->psy_ps);
|
|
power_supply_unregister(battery->psy_wireless);
|
|
power_supply_unregister(battery->psy_ac);
|
|
power_supply_unregister(battery->psy_usb);
|
|
power_supply_unregister(battery->psy_bat);
|
|
|
|
dev_dbg(battery->dev, "%s: End\n", __func__);
|
|
kfree(battery);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sec_battery_prepare(struct device *dev)
|
|
{
|
|
struct sec_battery_info *battery
|
|
= dev_get_drvdata(dev);
|
|
|
|
dev_info(battery->dev, "%s: Start\n", __func__);
|
|
|
|
switch (battery->pdata->polling_type) {
|
|
case SEC_BATTERY_MONITOR_WORKQUEUE:
|
|
cancel_delayed_work(&battery->polling_work);
|
|
break;
|
|
case SEC_BATTERY_MONITOR_ALARM:
|
|
alarm_cancel(&battery->polling_alarm);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* monitor_wake_lock should be unlocked before canceling monitor_work */
|
|
wake_unlock(&battery->monitor_wake_lock);
|
|
cancel_delayed_work_sync(&battery->monitor_work);
|
|
|
|
battery->polling_in_sleep = true;
|
|
|
|
sec_bat_set_polling(battery);
|
|
|
|
/* cancel work for polling
|
|
* that is set in sec_bat_set_polling()
|
|
* no need for polling in sleep
|
|
*/
|
|
if (battery->pdata->polling_type ==
|
|
SEC_BATTERY_MONITOR_WORKQUEUE)
|
|
cancel_delayed_work(&battery->polling_work);
|
|
|
|
dev_info(battery->dev, "%s: End\n", __func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sec_battery_suspend(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int sec_battery_resume(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void sec_battery_complete(struct device *dev)
|
|
{
|
|
struct sec_battery_info *battery
|
|
= dev_get_drvdata(dev);
|
|
|
|
dev_info(battery->dev, "%s: Start\n", __func__);
|
|
|
|
/* cancel current alarm and reset after monitor work */
|
|
if (battery->pdata->polling_type == SEC_BATTERY_MONITOR_ALARM)
|
|
alarm_cancel(&battery->polling_alarm);
|
|
|
|
wake_lock(&battery->monitor_wake_lock);
|
|
queue_delayed_work(battery->monitor_wqueue,
|
|
&battery->monitor_work, 0);
|
|
|
|
dev_info(battery->dev, "%s: End\n", __func__);
|
|
|
|
return;
|
|
}
|
|
|
|
static void sec_battery_shutdown(struct platform_device *pdev)
|
|
{
|
|
struct sec_battery_info *battery
|
|
= platform_get_drvdata(pdev);
|
|
|
|
switch (battery->pdata->polling_type) {
|
|
case SEC_BATTERY_MONITOR_WORKQUEUE:
|
|
cancel_delayed_work(&battery->polling_work);
|
|
break;
|
|
case SEC_BATTERY_MONITOR_ALARM:
|
|
alarm_cancel(&battery->polling_alarm);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_OF
|
|
static struct of_device_id sec_battery_dt_ids[] = {
|
|
{ .compatible = "samsung,sec-battery" },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, sec_battery_dt_ids);
|
|
#endif /* CONFIG_OF */
|
|
|
|
static const struct dev_pm_ops sec_battery_pm_ops = {
|
|
.prepare = sec_battery_prepare,
|
|
.suspend = sec_battery_suspend,
|
|
.resume = sec_battery_resume,
|
|
.complete = sec_battery_complete,
|
|
};
|
|
|
|
static struct platform_driver sec_battery_driver = {
|
|
.driver = {
|
|
.name = "sec-battery",
|
|
.owner = THIS_MODULE,
|
|
.pm = &sec_battery_pm_ops,
|
|
#ifdef CONFIG_OF
|
|
.of_match_table = sec_battery_dt_ids,
|
|
#endif
|
|
},
|
|
.probe = sec_battery_probe,
|
|
.remove = sec_battery_remove,
|
|
.shutdown = sec_battery_shutdown,
|
|
};
|
|
|
|
static int __init sec_battery_init(void)
|
|
{
|
|
return platform_driver_register(&sec_battery_driver);
|
|
}
|
|
|
|
static void __exit sec_battery_exit(void)
|
|
{
|
|
platform_driver_unregister(&sec_battery_driver);
|
|
}
|
|
|
|
late_initcall(sec_battery_init);
|
|
module_exit(sec_battery_exit);
|
|
|
|
MODULE_DESCRIPTION("Samsung Battery Driver");
|
|
MODULE_AUTHOR("Samsung Electronics");
|
|
MODULE_LICENSE("GPL");
|