diff options
Diffstat (limited to 'drivers/battery/samsung_battery_s2plus.c')
-rw-r--r-- | drivers/battery/samsung_battery_s2plus.c | 1273 |
1 files changed, 0 insertions, 1273 deletions
diff --git a/drivers/battery/samsung_battery_s2plus.c b/drivers/battery/samsung_battery_s2plus.c deleted file mode 100644 index 8f26e4f..0000000 --- a/drivers/battery/samsung_battery_s2plus.c +++ /dev/null @@ -1,1273 +0,0 @@ -/* - * samsung_battery.c - * - * Copyright (C) 2011 Samsung Electronics - * SangYoung Son <hello.son@samsung.com> - * - * based on sec_battery.c - * - * Copyright (C) 2012 Samsung Electronics - * Jaecheol Kim <jc22.kim@samsung.com> - * - * add sub-charger based on samsung_battery.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/reboot.h> -#include <linux/jiffies.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/wakelock.h> -#include <linux/workqueue.h> -#include <linux/proc_fs.h> -#include <linux/android_alarm.h> -#include <linux/battery/samsung_battery.h> -#include <mach/regs-pmu.h> -#include "battery-factory.h" -#if defined(CONFIG_S3C_ADC) -#include <plat/adc.h> -#endif - -static char *supply_list[] = { - "battery", -}; - -/* Get LP charging mode state */ -unsigned int lpcharge; -static int battery_get_lpm_state(char *str) -{ - get_option(&str, &lpcharge); - pr_info("%s: Low power charging mode: %d\n", __func__, lpcharge); - - return lpcharge; -} -__setup("lpcharge=", battery_get_lpm_state); - -/* Temperature from fuelgauge or adc */ -static int battery_get_temper(struct battery_info *info) -{ - union power_supply_propval value; - int temper = 0; - int retry_cnt = 0; - pr_debug("%s\n", __func__); - - switch (info->pdata->temper_src) { - case TEMPER_FUELGAUGE: - info->psy_fuelgauge->get_property(info->psy_fuelgauge, - POWER_SUPPLY_PROP_TEMP, &value); - temper = value.intval; - break; - case TEMPER_AP_ADC: -#if defined(CONFIG_S3C_ADC) - do { - info->battery_temper_adc = - s3c_adc_read(info->adc_client, - info->pdata->temper_ch); - - if (info->battery_temper_adc < 0) { - pr_info("%s: adc read(%d), retry(%d)", __func__, - info->battery_temper_adc, retry_cnt); - retry_cnt++; - msleep(100); - } - } while ((info->battery_temper_adc < 0) && (retry_cnt <= 5)); - - if (info->battery_temper_adc < 0) { - pr_info("%s: adc read error(%d), temper set as 30.0", - __func__, info->battery_temper_adc); - temper = 300; - } else { - temper = info->pdata->covert_adc( - info->battery_temper_adc, - info->pdata->temper_ch); - } -#endif - break; - case TEMPER_EXT_ADC: -#if defined(CONFIG_STMPE811_ADC) - temper = stmpe811_get_adc_value(info->pdata->temper_ch); -#endif - break; - case TEMPER_UNKNOWN: - default: - pr_info("%s: invalid temper src(%d)\n", __func__, - info->pdata->temper_src); - temper = 300; - break; - } - - pr_debug("%s: temper(%d), source(%d)\n", __func__, - temper, info->pdata->temper_src); - return temper; -} - -/* Get info from power supply at realtime */ -int battery_get_info(struct battery_info *info, - enum power_supply_property property) -{ - union power_supply_propval value; - value.intval = 0; - - if (info->battery_error_test) { - pr_info("%s: in test mode(%d), do not update\n", __func__, - info->battery_error_test); - return -EPERM; - } - - switch (property) { - /* Update from charger */ - case POWER_SUPPLY_PROP_CHARGE_TYPE: - case POWER_SUPPLY_PROP_HEALTH: - case POWER_SUPPLY_PROP_PRESENT: - case POWER_SUPPLY_PROP_ONLINE: - info->psy_charger->get_property(info->psy_charger, - property, &value); - break; - case POWER_SUPPLY_PROP_STATUS: - case POWER_SUPPLY_PROP_CURRENT_NOW: - if (info->use_sub_charger) { - info->psy_sub_charger->get_property(info->psy_sub_charger, - property, &value); - } else { - info->psy_charger->get_property(info->psy_charger, - property, &value); - } - break; - /* Update from fuelgauge */ - case POWER_SUPPLY_PROP_CAPACITY: /* Only Adjusted SOC */ - case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* Only VCELL */ - info->psy_fuelgauge->get_property(info->psy_fuelgauge, - property, &value); - break; - /* Update from fuelgauge or adc */ - case POWER_SUPPLY_PROP_TEMP: - value.intval = battery_get_temper(info); - break; - default: - break; - } - - return value.intval; -} - -/* Update all values for battery */ -void battery_update_info(struct battery_info *info) -{ - union power_supply_propval value; - - if (info->use_sub_charger) { - /* Update from Charger */ - info->psy_sub_charger->get_property(info->psy_sub_charger, - POWER_SUPPLY_PROP_STATUS, &value); - info->charge_real_state = info->charge_virt_state = value.intval; - - info->psy_sub_charger->get_property(info->psy_sub_charger, - POWER_SUPPLY_PROP_CURRENT_NOW, &value); - info->charge_current = value.intval; - - } else { - /* Update from Charger */ - info->psy_charger->get_property(info->psy_charger, - POWER_SUPPLY_PROP_STATUS, &value); - info->charge_real_state = info->charge_virt_state = value.intval; - - info->psy_charger->get_property(info->psy_charger, - POWER_SUPPLY_PROP_CURRENT_NOW, &value); - info->charge_current = value.intval; - } - - info->psy_charger->get_property(info->psy_charger, - POWER_SUPPLY_PROP_HEALTH, &value); - info->battery_health = value.intval; - - info->psy_charger->get_property(info->psy_charger, - POWER_SUPPLY_PROP_PRESENT, &value); - info->battery_present = value.intval; - - info->psy_charger->get_property(info->psy_charger, - POWER_SUPPLY_PROP_ONLINE, &value); - info->cable_type = value.intval; - - info->psy_charger->get_property(info->psy_charger, - POWER_SUPPLY_PROP_CHARGE_TYPE, &value); - info->charge_type = value.intval; - - /* Fuelgauge power off state */ - if ((info->cable_type != POWER_SUPPLY_TYPE_BATTERY) && - (info->battery_present == 0)) { - pr_info("%s: Abnormal fuelgauge power state\n", __func__); - goto update_finish; - } - - /* Update from Fuelgauge */ - value.intval = SOC_TYPE_ADJUSTED; - info->psy_fuelgauge->get_property(info->psy_fuelgauge, - POWER_SUPPLY_PROP_CAPACITY, &value); - info->battery_soc = value.intval; - - value.intval = SOC_TYPE_RAW; - info->psy_fuelgauge->get_property(info->psy_fuelgauge, - POWER_SUPPLY_PROP_CAPACITY, &value); - info->battery_raw_soc = value.intval; - - value.intval = VOLTAGE_TYPE_VCELL; - info->psy_fuelgauge->get_property(info->psy_fuelgauge, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - &value); - info->battery_vcell = value.intval; - - value.intval = VOLTAGE_TYPE_VFOCV; - info->psy_fuelgauge->get_property(info->psy_fuelgauge, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - &value); - info->battery_vfocv = value.intval; - - info->battery_temper = battery_get_temper(info); - -update_finish: - switch (info->battery_error_test) { - case 0: - pr_debug("%s: error test: normal state\n", __func__); - break; - case 1: - pr_info("%s: error test: full charged\n", __func__); - info->charge_real_state = POWER_SUPPLY_STATUS_FULL; - info->battery_vcell = 4200000; - info->battery_soc = 100; - break; - case 2: - pr_info("%s: error test: freezed\n", __func__); - info->battery_temper = info->pdata->freeze_stop_temp - 10; - break; - case 3: - pr_info("%s: error test: overheated\n", __func__); - info->battery_temper = info->pdata->overheat_stop_temp + 10; - break; - case 4: - pr_info("%s: error test: ovp\n", __func__); - break; - case 5: - pr_info("%s: error test: vf error\n", __func__); - info->battery_present = 0; - break; - default: - pr_info("%s: error test: unknown state\n", __func__); - break; - } - - pr_debug("%s: state(%d), type(%d), " - "health(%d), present(%d), " - "cable(%d), curr(%d), " - "soc(%d), raw(%d), " - "vol(%d), ocv(%d), tmp(%d)\n", __func__, - info->charge_real_state, info->charge_type, - info->battery_health, info->battery_present, - info->cable_type, info->charge_current, - info->battery_soc, info->battery_raw_soc, - info->battery_vcell, info->battery_vfocv, - info->battery_temper); -} - -/* Control charger and fuelgauge */ -void battery_control_info(struct battery_info *info, - enum power_supply_property property, int intval) -{ - union power_supply_propval value; - - value.intval = intval; - - switch (property) { - /* Control to charger */ - case POWER_SUPPLY_PROP_STATUS: - case POWER_SUPPLY_PROP_CURRENT_NOW: - if (info->use_sub_charger) { - info->psy_sub_charger->set_property(info->psy_sub_charger, - property, &value); - } else { - info->psy_charger->set_property(info->psy_charger, - property, &value); - } - break; - - /* Control to fuelgauge */ - case POWER_SUPPLY_PROP_CAPACITY: - info->psy_fuelgauge->set_property(info->psy_fuelgauge, - property, &value); - break; - default: - break; - } -} - -/* Support property from battery */ -static enum power_supply_property samsung_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_CURRENT_NOW, - POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_TEMP, -}; - -/* Support property from usb, ac */ -static enum power_supply_property samsung_power_props[] = { - POWER_SUPPLY_PROP_ONLINE, -}; - -static int samsung_battery_get_property(struct power_supply *ps, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct battery_info *info = container_of(ps, struct battery_info, - psy_bat); - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = info->charge_virt_state; - break; - case POWER_SUPPLY_PROP_CHARGE_TYPE: - val->intval = info->charge_type; - break; - case POWER_SUPPLY_PROP_HEALTH: - val->intval = info->battery_health; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = info->battery_present; - break; - case POWER_SUPPLY_PROP_ONLINE: - val->intval = info->cable_type; - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = info->battery_vcell; - break; - case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = info->charge_current; - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = info->battery_soc; - break; - case POWER_SUPPLY_PROP_TEMP: - val->intval = info->battery_temper; - break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = POWER_SUPPLY_TECHNOLOGY_LION; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int samsung_battery_set_property(struct power_supply *ps, - enum power_supply_property psp, - const union power_supply_propval *val) -{ - struct battery_info *info = container_of(ps, struct battery_info, - psy_bat); - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - case POWER_SUPPLY_PROP_CHARGE_TYPE: - case POWER_SUPPLY_PROP_HEALTH: - case POWER_SUPPLY_PROP_PRESENT: - case POWER_SUPPLY_PROP_ONLINE: - case POWER_SUPPLY_PROP_TECHNOLOGY: - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - case POWER_SUPPLY_PROP_CURRENT_NOW: - case POWER_SUPPLY_PROP_CAPACITY: - case POWER_SUPPLY_PROP_TEMP: - break; - default: - return -EINVAL; - } - - wake_lock(&info->monitor_wake_lock); - schedule_work(&info->monitor_work); - - return 0; -} - -static int samsung_usb_get_property(struct power_supply *ps, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct battery_info *info = container_of(ps, struct battery_info, - psy_usb); - - if (psp != POWER_SUPPLY_PROP_ONLINE) - return -EINVAL; - - /* Set enable=1 only if the USB charger is connected */ - val->intval = (info->cable_type == POWER_SUPPLY_TYPE_USB) || - (info->cable_type == POWER_SUPPLY_TYPE_USB_CDP); - - return 0; -} - -static int samsung_ac_get_property(struct power_supply *ps, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct battery_info *info = container_of(ps, struct battery_info, - psy_ac); - - if (psp != POWER_SUPPLY_PROP_ONLINE) - return -EINVAL; - - /* Set enable=1 only if the AC charger is connected */ - val->intval = (info->cable_type == POWER_SUPPLY_TYPE_MAINS) || - (info->cable_type == POWER_SUPPLY_TYPE_MISC) || - (info->cable_type == POWER_SUPPLY_TYPE_WIRELESS); - - return 0; -} - -static void samsung_battery_alarm_start(struct alarm *alarm) -{ - struct battery_info *info = container_of(alarm, struct battery_info, - alarm); - pr_debug("%s\n", __func__); - - wake_lock(&info->monitor_wake_lock); - schedule_work(&info->monitor_work); -} - -static void samsung_battery_next_monitor(struct battery_info *info) -{ - ktime_t interval, next; - unsigned long flags; - pr_debug("%s\n", __func__); - - local_irq_save(flags); - - info->last_poll = alarm_get_elapsed_realtime(); - - switch (info->monitor_mode) { - case MONITOR_CHNG: - info->monitor_interval = info->pdata->chng_interval; - break; - case MONITOR_CHNG_SUSP: - info->monitor_interval = info->pdata->chng_susp_interval; - break; - case MONITOR_NORM: - info->monitor_interval = info->pdata->norm_interval; - break; - case MONITOR_NORM_SUSP: - info->monitor_interval = info->pdata->norm_susp_interval; - break; - case MONITOR_EMER: - info->monitor_interval = info->pdata->emer_interval; - break; - default: - info->monitor_interval = info->pdata->norm_interval; - break; - } - - pr_debug("%s: monitor mode(%d), interval(%d)\n", __func__, - info->monitor_mode, info->monitor_interval); - - interval = ktime_set(info->monitor_interval, 0); - next = ktime_add(info->last_poll, interval); - alarm_start_range(&info->alarm, next, next); - - local_irq_restore(flags); -} - -static bool battery_recharge_cond(struct battery_info *info) -{ - pr_debug("%s\n", __func__); - - if (info->charge_real_state == POWER_SUPPLY_STATUS_CHARGING) { - pr_debug("%s: not recharge cond., now charging\n", __func__); - return false; - } - - if (info->battery_vcell < info->pdata->recharge_voltage) { - pr_info("%s: recharge start(%d ?? %d)\n", __func__, - info->battery_vcell, info->pdata->recharge_voltage); - return true; - } else - pr_debug("%s: not recharge cond., vcell is enough\n", __func__); - - return false; -} - -static bool battery_abstimer_cond(struct battery_info *info) -{ - unsigned int abstimer_duration; - ktime_t ktime; - struct timespec current_time; - pr_debug("%s\n", __func__); - - if ((info->cable_type != POWER_SUPPLY_TYPE_MAINS) || - (info->full_charged_state == true) || - (info->charge_start_time == 0)) { - info->abstimer_state = false; - return false; - } - - ktime = alarm_get_elapsed_realtime(); - current_time = ktime_to_timespec(ktime); - - if (info->recharge_phase) - abstimer_duration = info->pdata->abstimer_recharge_duration; - else - abstimer_duration = info->pdata->abstimer_charge_duration; - - if ((current_time.tv_sec - info->charge_start_time) > - abstimer_duration) { - pr_info("%s: charge time out(%d - %d ?? %d)\n", __func__, - (int)current_time.tv_sec, - info->charge_start_time, - abstimer_duration); - info->abstimer_state = true; - } else { - pr_debug("%s: not abstimer condition\n", __func__); - info->abstimer_state = false; - } - - return info->abstimer_state; -} - -static bool battery_fullcharged_cond(struct battery_info *info) -{ - pr_debug("%s\n", __func__); - - if ((info->charge_real_state == POWER_SUPPLY_STATUS_FULL) && - (info->battery_vcell > 4150000) && - (info->battery_soc > 95)) { - pr_info("%s: real full charged(%d, %d)\n", __func__, - info->battery_vcell, info->battery_soc); - info->full_charged_state = true; - return true; - } else if (info->full_charged_state == true) { - pr_debug("%s: already full charged\n", __func__); - } else { - pr_debug("%s: not full charged\n", __func__); - info->full_charged_state = false; - } - - /* Add some more full charged case(current sensing, etc...) */ - - return false; -} - -static bool battery_vf_cond(struct battery_info *info) -{ - pr_debug("%s\n", __func__); - -#if defined(CONFIG_MACH_P11) - /* FIXME: fix P11 build error temporarily */ -#else - /* jig detect by MUIC */ - if (is_jig_attached == JIG_ON) { - pr_info("%s: JIG ON, do not check\n", __func__); - info->vf_state = false; - return false; - } -#endif - - /* TODO: Check VF from ADC */ - - /* Now, battery present from charger */ - info->battery_present = - battery_get_info(info, POWER_SUPPLY_PROP_PRESENT); - if (info->battery_present == 0) { - pr_info("%s: battery is not detected.\n", __func__); - info->vf_state = true; - } else { - pr_debug("%s: battery is detected.\n", __func__); - info->vf_state = false; - } - - return info->vf_state; -} - -static bool battery_health_cond(struct battery_info *info) -{ - pr_debug("%s\n", __func__); - - if (info->battery_health == POWER_SUPPLY_HEALTH_DEAD) { - pr_info("%s: battery dead(%d)\n", __func__, - info->battery_health); - info->health_state = true; - } else if (info->battery_health == POWER_SUPPLY_HEALTH_OVERVOLTAGE) { - pr_info("%s: battery overvoltage(%d)\n", __func__, - info->battery_health); - info->health_state = true; - } else { - pr_debug("%s: battery good(%d)\n", __func__, - info->battery_health); - info->health_state = false; - } - - return info->health_state; -} - -static bool battery_temp_cond(struct battery_info *info) -{ - pr_debug("%s\n", __func__); - - if (info->temperature_state == false) { - if (info->charge_real_state != POWER_SUPPLY_STATUS_CHARGING) { - pr_debug("%s: not charging state\n", __func__); - return false; - } - - pr_debug("%s: check charging stop temp." - "cond: %d ?? %d ~ %d\n", __func__, - info->battery_temper, - info->pdata->freeze_stop_temp, - info->pdata->overheat_stop_temp); - - if (info->battery_temper >= - info->pdata->overheat_stop_temp) { - pr_info("%s: stop by overheated temp\n", __func__); - info->overheated_state = true; - } else if (info->battery_temper <= - info->pdata->freeze_stop_temp) { - pr_info("%s: stop by freezed temp\n", __func__); - info->freezed_state = true; - } else - pr_debug("%s: normal charging temp\n", __func__); - } else { - pr_debug("%s: check charging recovery temp." - "cond: %d ?? %d ~ %d\n", __func__, - info->battery_temper, - info->pdata->freeze_recovery_temp, - info->pdata->overheat_recovery_temp); - - if ((info->overheated_state == true) && - (info->battery_temper <= - info->pdata->overheat_recovery_temp)) { - pr_info("%s: recovery from overheated\n", - __func__); - info->overheated_state = false; - } else if ((info->freezed_state == true) && - (info->battery_temper >= - info->pdata->freeze_recovery_temp)) { - pr_info("%s: recovery from freezed\n", - __func__); - info->freezed_state = false; - } else - pr_info("%s: charge stopped temp\n", __func__); - } - - if (info->overheated_state == true) { - info->battery_health = POWER_SUPPLY_HEALTH_OVERHEAT; - info->freezed_state = false; - info->temperature_state = true; - } else if (info->freezed_state == true) { - info->battery_health = POWER_SUPPLY_HEALTH_COLD; - info->overheated_state = false; - info->temperature_state = true; - } else { - info->overheated_state = false; - info->freezed_state = false; - info->temperature_state = false; - } - - return info->temperature_state; -} - -static void battery_charge_control(struct battery_info *info, - int enable, - int set_current) -{ - ktime_t ktime; - struct timespec current_time; - pr_debug("%s\n", __func__); - - ktime = alarm_get_elapsed_realtime(); - current_time = ktime_to_timespec(ktime); - - if (set_current == CHARGER_KEEP_CURRENT) - goto charge_state_control; - - if (!info->use_sub_charger) { - if (info->siop_state == true) { - pr_debug("%s: siop state, charge current is %dmA\n", __func__, - info->siop_charge_current); - set_current = info->siop_charge_current; - } - - /* check charge current before and after */ - if (info->charge_current == ((set_current * 3 / 100) * 333 / 10)) { - /* - * (current * 3 / 100) is converted value - * for register setting. - * (register current * 333 / 10) is actual value - * for charging - */ - pr_debug("%s: same charge current: %dmA\n", __func__, - set_current); - } else { - battery_control_info(info, - POWER_SUPPLY_PROP_CURRENT_NOW, - set_current); - pr_info("%s: update charge current: %dmA\n", __func__, - set_current); - } - } - - info->charge_current = - battery_get_info(info, POWER_SUPPLY_PROP_CURRENT_NOW); - -charge_state_control: - /* check charge state before and after */ - if ((enable == CHARGE_ENABLE) && - (info->charge_start_time == 0)) { - battery_control_info(info, - POWER_SUPPLY_PROP_STATUS, - CHARGE_ENABLE); - - info->charge_start_time = current_time.tv_sec; - pr_info("%s: charge enabled, current as %dmA @%d\n", __func__, - info->charge_current, info->charge_start_time); - } else if ((enable == CHARGE_DISABLE) && - (info->charge_start_time != 0)) { - battery_control_info(info, - POWER_SUPPLY_PROP_STATUS, - CHARGE_DISABLE); - - pr_info("%s: charge disabled, current as %dmA @%d\n", __func__, - info->charge_current, (int)current_time.tv_sec); - - info->charge_start_time = 0; - } else { - pr_debug("%s: same charge state(%s), current as %dmA @%d\n", - __func__, (enable ? "enabled" : "disabled"), - info->charge_current, info->charge_start_time); - } - - info->charge_real_state = - battery_get_info(info, POWER_SUPPLY_PROP_STATUS); -} - -static void battery_monitor_work(struct work_struct *work) -{ - struct battery_info *info = container_of(work, struct battery_info, - monitor_work); - pr_debug("%s\n", __func__); - - /* If battery is not connected, clear flag for charge scenario */ - if (battery_vf_cond(info) == true) { - pr_info("%s: battery error\n", __func__); - info->overheated_state = false; - info->freezed_state = false; - info->temperature_state = false; - info->full_charged_state = false; - info->abstimer_state = false; - info->recharge_phase = false; - - schedule_work(&info->error_work); - } - - /* Check battery state from charger and fuelgauge */ - battery_update_info(info); - - /* If charger is not connected, do not check charge scenario */ - if (info->cable_type == POWER_SUPPLY_TYPE_BATTERY) - goto charge_ok; - - /* Below is charger is connected state */ - if (battery_temp_cond(info) == true) { - pr_info("%s: charge stopped by temperature\n", __func__); - battery_charge_control(info, - CHARGE_DISABLE, CHARGER_OFF_CURRENT); - goto monitor_finish; - } - - if (battery_health_cond(info) == true) { - pr_info("%s: bad health state\n", __func__); - goto monitor_finish; - } - - if (battery_fullcharged_cond(info) == true) { - pr_info("%s: full charged state\n", __func__); - battery_charge_control(info, - CHARGE_DISABLE, CHARGER_KEEP_CURRENT); - info->recharge_phase = true; - goto monitor_finish; - } - - if (battery_abstimer_cond(info) == true) { - pr_info("%s: abstimer state\n", __func__); - battery_charge_control(info, - CHARGE_DISABLE, CHARGER_OFF_CURRENT); - info->recharge_phase = true; - goto monitor_finish; - } - - if (info->recharge_phase == true) { - if (battery_recharge_cond(info) == true) { - pr_info("%s: recharge condition\n", __func__); - goto charge_ok; - } else { - pr_debug("%s: not recharge\n", __func__); - goto monitor_finish; - } - } - -charge_ok: - switch (info->cable_type) { - case POWER_SUPPLY_TYPE_BATTERY: - if (!info->pdata->suspend_chging) - wake_unlock(&info->charge_wake_lock); - battery_charge_control(info, - CHARGE_DISABLE, CHARGER_OFF_CURRENT); - info->charge_virt_state = POWER_SUPPLY_STATUS_DISCHARGING; - - /* clear charge scenario state */ - info->overheated_state = false; - info->freezed_state = false; - info->temperature_state = false; - info->full_charged_state = false; - info->abstimer_state = false; - info->recharge_phase = false; - break; - case POWER_SUPPLY_TYPE_MAINS: - if (!info->pdata->suspend_chging) - wake_lock(&info->charge_wake_lock); - battery_charge_control(info, CHARGE_ENABLE, CHARGER_AC_CURRENT_S2PLUS); - info->charge_virt_state = POWER_SUPPLY_STATUS_CHARGING; - break; - case POWER_SUPPLY_TYPE_USB: - if (!info->pdata->suspend_chging) - wake_lock(&info->charge_wake_lock); - battery_charge_control(info, - CHARGE_ENABLE, CHARGER_USB_CURRENT); - info->charge_virt_state = POWER_SUPPLY_STATUS_CHARGING; - break; - case POWER_SUPPLY_TYPE_USB_CDP: - if (!info->pdata->suspend_chging) - wake_lock(&info->charge_wake_lock); - battery_charge_control(info, - CHARGE_ENABLE, CHARGER_CDP_CURRENT); - info->charge_virt_state = POWER_SUPPLY_STATUS_CHARGING; - break; - case POWER_SUPPLY_TYPE_WIRELESS: - if (!info->pdata->suspend_chging) - wake_lock(&info->charge_wake_lock); - battery_charge_control(info, - CHARGE_ENABLE, CHARGER_WPC_CURRENT); - info->charge_virt_state = POWER_SUPPLY_STATUS_CHARGING; - break; - default: - break; - } - -monitor_finish: - /* Overwrite charge state for UI(icon) */ - if (info->full_charged_state == true) { - info->charge_virt_state = POWER_SUPPLY_STATUS_FULL; - info->battery_soc = 100; - } else if (info->abstimer_state == true) { - info->charge_virt_state = POWER_SUPPLY_STATUS_CHARGING; - } else if (info->recharge_phase == true) { - info->charge_virt_state = POWER_SUPPLY_STATUS_CHARGING; - } - - if (info->cable_type != POWER_SUPPLY_TYPE_BATTERY) { - if (info->temperature_state == true) - info->charge_virt_state = - POWER_SUPPLY_STATUS_NOT_CHARGING; - - if (info->vf_state == true) { - info->charge_virt_state = - POWER_SUPPLY_STATUS_NOT_CHARGING; - /* to be considered */ - info->battery_health = - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; - } - - if (info->health_state == true) - info->charge_virt_state = - POWER_SUPPLY_STATUS_NOT_CHARGING; - } - - /* monitoring interval */ - if (info->charge_virt_state == POWER_SUPPLY_STATUS_NOT_CHARGING) { - pr_debug("%s: emergency(not charging) state\n", __func__); - info->monitor_mode = MONITOR_EMER; - wake_lock(&info->emer_wake_lock); - } else { - pr_debug("%s: normal state\n", __func__); - info->monitor_mode = MONITOR_NORM; - wake_unlock(&info->emer_wake_lock); - } - - pr_info("bat: s(%d), v(%d, %d), b(%d), " - "t(%d.%d), h(%d), " - "ch(%d, %d), cb(%d), cr(%d), " - "abs(%d), f(%d), rch(%d), t(%d)\n", - info->battery_soc, - info->battery_vcell / 1000, - info->battery_vfocv / 1000, - info->battery_present, - info->battery_temper / 10, info->battery_temper % 10, - info->battery_health, - info->charge_real_state, - info->charge_virt_state, - info->cable_type, - info->charge_current, - info->abstimer_state, - info->full_charged_state, - info->recharge_phase, info->charge_start_time); - - /* - * WORKAROUND: Do not power off, if vell is over 3400mV - */ - if (info->battery_soc == 0) { - if (info->battery_vcell > 3400) { - pr_info("%s: soc 0%%, but vcell(%d) is over 3400mV, " - "do not power off\n", - __func__, info->battery_vcell); - info->battery_soc = 1; - } - } - - power_supply_changed(&info->psy_bat); - - /* prevent suspend before starting the alarm */ - samsung_battery_next_monitor(info); - - wake_unlock(&info->monitor_wake_lock); - - return; -} - -static void battery_error_work(struct work_struct *work) -{ - struct battery_info *info = container_of(work, struct battery_info, - error_work); - int err_cnt; - int old_vcell, new_vcell, vcell_diff; - pr_info("%s\n", __func__); - - if (info->vf_state == true) { - pr_info("%s: battery error state\n", __func__); - old_vcell = info->battery_vcell; - new_vcell = 0; - for (err_cnt = 1; err_cnt <= VF_CHECK_COUNT; err_cnt++) { - /* check jig first */ - if (is_jig_attached == JIG_ON) { - pr_info("%s: JIG detected, return\n", __func__); - return; - } - info->battery_present = - battery_get_info(info, - POWER_SUPPLY_PROP_PRESENT); - if (info->battery_present == 0) { - pr_info("%s: battery still error(%d)\n", - __func__, err_cnt); - msleep(VF_CHECK_DELAY); - } else { - pr_info("%s: battery detect ok, " - "check soc\n", __func__); - new_vcell = battery_get_info(info, - POWER_SUPPLY_PROP_VOLTAGE_NOW); - vcell_diff = abs(old_vcell - new_vcell); - pr_info("%s: check vcell: %d -> %d, diff: %d\n", - __func__, info->battery_vcell, - new_vcell, vcell_diff); - if (vcell_diff > RESET_SOC_DIFF_TH) { - pr_info("%s: reset soc\n", __func__); - battery_control_info(info, - POWER_SUPPLY_PROP_CAPACITY, 1); - } else - pr_info("%s: keep soc\n", __func__); - break; - } - - if (err_cnt == VF_CHECK_COUNT) { - pr_info("%s: battery error, power off\n", - __func__); - battery_charge_control(info, - CHARGE_DISABLE, CHARGER_OFF_CURRENT); - } - } - } - - return; -} - -static __devinit int samsung_battery_probe(struct platform_device *pdev) -{ - struct battery_info *info; - int ret = 0; - char *temper_src_name[] = { "fuelgauge", "ap adc", - "ext adc", "unknown" - }; - pr_info("%s: SAMSUNG Battery Driver Loading\n", __func__); - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - platform_set_drvdata(pdev, info); - - info->dev = &pdev->dev; - info->pdata = pdev->dev.platform_data; - - /* Check charger name and fuelgauge name. */ - if (!info->pdata->charger_name || !info->pdata->fuelgauge_name) { - pr_err("%s: no charger or fuel gauge name\n", __func__); - goto err_kfree; - } - info->charger_name = info->pdata->charger_name; - info->fuelgauge_name = info->pdata->fuelgauge_name; - - pr_info("%s: Charger name: %s\n", __func__, info->charger_name); - pr_info("%s: Fuelgauge name: %s\n", __func__, info->fuelgauge_name); - - info->psy_charger = power_supply_get_by_name(info->charger_name); - info->psy_fuelgauge = power_supply_get_by_name(info->fuelgauge_name); - - if (!info->psy_charger || !info->psy_fuelgauge) { - pr_err("%s: fail to get power supply\n", __func__); - goto err_kfree; - } - - info->use_sub_charger = info->pdata->use_sub_charger; - if (info->use_sub_charger) { - info->sub_charger_name = info->pdata->sub_charger_name; - pr_info("%s: subcharger name: %s\n", __func__, - info->sub_charger_name); - info->psy_sub_charger = power_supply_get_by_name(info->sub_charger_name); - - if (!info->psy_sub_charger) { - pr_err("%s fail to get sub charger\n", __func__); - goto err_kfree; - } - } - /* force set S2PLUS recharge voltage */ - info->pdata->recharge_voltage = 4150000; - - pr_info("%s: Temperature source: %s\n", __func__, - temper_src_name[info->pdata->temper_src]); - pr_info("%s: Recharge voltage: %d\n", __func__, - info->pdata->recharge_voltage); - -#if defined(CONFIG_S3C_ADC) - info->adc_client = s3c_adc_register(pdev, NULL, NULL, 0); -#endif - - /* init battery info */ - info->full_charged_state = false; - info->abstimer_state = false; - info->recharge_phase = false; - info->siop_charge_current = CHARGER_USB_CURRENT; - info->monitor_mode = MONITOR_NORM; - - /* LPM charging state */ - info->lpm_state = lpcharge; - - wake_lock_init(&info->monitor_wake_lock, WAKE_LOCK_SUSPEND, - "battery-monitor"); - wake_lock_init(&info->emer_wake_lock, WAKE_LOCK_SUSPEND, - "battery-emergency"); - if (!info->pdata->suspend_chging) - wake_lock_init(&info->charge_wake_lock, - WAKE_LOCK_SUSPEND, "battery-charging"); - - /* Init wq for battery */ - INIT_WORK(&info->error_work, battery_error_work); - INIT_WORK(&info->monitor_work, battery_monitor_work); - - /* Init Power supply class */ - info->psy_bat.name = "battery"; - info->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY; - info->psy_bat.properties = samsung_battery_props; - info->psy_bat.num_properties = ARRAY_SIZE(samsung_battery_props); - info->psy_bat.get_property = samsung_battery_get_property; - info->psy_bat.set_property = samsung_battery_set_property; - - info->psy_usb.name = "usb"; - info->psy_usb.type = POWER_SUPPLY_TYPE_USB; - info->psy_usb.supplied_to = supply_list; - info->psy_usb.num_supplicants = ARRAY_SIZE(supply_list); - info->psy_usb.properties = samsung_power_props; - info->psy_usb.num_properties = ARRAY_SIZE(samsung_power_props); - info->psy_usb.get_property = samsung_usb_get_property; - - info->psy_ac.name = "ac"; - info->psy_ac.type = POWER_SUPPLY_TYPE_MAINS; - info->psy_ac.supplied_to = supply_list; - info->psy_ac.num_supplicants = ARRAY_SIZE(supply_list); - info->psy_ac.properties = samsung_power_props; - info->psy_ac.num_properties = ARRAY_SIZE(samsung_power_props); - info->psy_ac.get_property = samsung_ac_get_property; - - ret = power_supply_register(&pdev->dev, &info->psy_bat); - if (ret) { - pr_err("%s: failed to register psy_bat\n", __func__); - goto err_psy_reg_bat; - } - - ret = power_supply_register(&pdev->dev, &info->psy_usb); - if (ret) { - pr_err("%s: failed to register psy_usb\n", __func__); - goto err_psy_reg_usb; - } - - ret = power_supply_register(&pdev->dev, &info->psy_ac); - if (ret) { - pr_err("%s: failed to register psy_ac\n", __func__); - goto err_psy_reg_ac; - } - - /* Using android alarm for gauging instead of workqueue */ - info->last_poll = alarm_get_elapsed_realtime(); - alarm_init(&info->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, - samsung_battery_alarm_start); - - /* update battery init status */ - schedule_work(&info->monitor_work); - - /* Create samsung detail attributes */ - battery_create_attrs(info->psy_bat.dev); - - pr_info("%s: SAMSUNG Battery Driver Loaded\n", __func__); - return 0; - - err_psy_reg_ac: - power_supply_unregister(&info->psy_usb); - err_psy_reg_usb: - power_supply_unregister(&info->psy_bat); - err_psy_reg_bat: - wake_lock_destroy(&info->monitor_wake_lock); - wake_lock_destroy(&info->emer_wake_lock); - if (!info->pdata->suspend_chging) - wake_lock_destroy(&info->charge_wake_lock); - err_kfree: - kfree(info); - - return ret; -} - -static int __devexit samsung_battery_remove(struct platform_device *pdev) -{ - struct battery_info *info = platform_get_drvdata(pdev); - - remove_proc_entry("battery_info_proc", NULL); - - cancel_work_sync(&info->error_work); - cancel_work_sync(&info->monitor_work); - - power_supply_unregister(&info->psy_bat); - power_supply_unregister(&info->psy_usb); - power_supply_unregister(&info->psy_ac); - - wake_lock_destroy(&info->monitor_wake_lock); - wake_lock_destroy(&info->emer_wake_lock); - if (!info->pdata->suspend_chging) - wake_lock_destroy(&info->charge_wake_lock); - - kfree(info); - - return 0; -} - -#ifdef CONFIG_PM -static int samsung_battery_prepare(struct device *dev) -{ - struct battery_info *info = dev_get_drvdata(dev); - pr_info("%s\n", __func__); - - if (info->monitor_mode != MONITOR_EMER) { - if (info->charge_real_state == POWER_SUPPLY_STATUS_CHARGING) - info->monitor_mode = MONITOR_CHNG_SUSP; - else - info->monitor_mode = MONITOR_NORM_SUSP; - } - - samsung_battery_next_monitor(info); - - return 0; -} - -static void samsung_battery_complete(struct device *dev) -{ - struct battery_info *info = dev_get_drvdata(dev); - pr_info("%s\n", __func__); - - info->monitor_mode = MONITOR_NORM; -} - -static int samsung_battery_suspend(struct device *dev) -{ - struct battery_info *info = dev_get_drvdata(dev); - pr_info("%s\n", __func__); - - flush_work_sync(&info->monitor_work); - - return 0; -} - -static int samsung_battery_resume(struct device *dev) -{ - struct battery_info *info = dev_get_drvdata(dev); - pr_info("%s\n", __func__); - - schedule_work(&info->monitor_work); - - return 0; -} - -static const struct dev_pm_ops samsung_battery_pm_ops = { - .prepare = samsung_battery_prepare, - .complete = samsung_battery_complete, - .suspend = samsung_battery_suspend, - .resume = samsung_battery_resume, -}; -#endif - -static struct platform_driver samsung_battery_driver = { - .driver = { - .name = "samsung-battery", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &samsung_battery_pm_ops, -#endif - }, - .probe = samsung_battery_probe, - .remove = __devexit_p(samsung_battery_remove), -}; - -static int __init samsung_battery_init(void) -{ - return platform_driver_register(&samsung_battery_driver); -} - -static void __exit samsung_battery_exit(void) -{ - platform_driver_unregister(&samsung_battery_driver); -} - -late_initcall(samsung_battery_init); -module_exit(samsung_battery_exit); - -MODULE_AUTHOR("Jaecheol Kim <jc22.kim@samsung.com>"); -MODULE_DESCRIPTION("SAMSUNG battery driver"); -MODULE_LICENSE("GPL"); |