aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/battery/samsung_battery.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/battery/samsung_battery.c')
-rw-r--r--drivers/battery/samsung_battery.c868
1 files changed, 691 insertions, 177 deletions
diff --git a/drivers/battery/samsung_battery.c b/drivers/battery/samsung_battery.c
index d1cee8f..c63430b 100644
--- a/drivers/battery/samsung_battery.c
+++ b/drivers/battery/samsung_battery.c
@@ -31,9 +31,13 @@
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/android_alarm.h>
+#include <linux/regulator/machine.h>
#include <linux/battery/samsung_battery.h>
#include <mach/regs-pmu.h>
#include "battery-factory.h"
+#ifdef CONFIG_BATTERY_MAX77693_CHARGER
+#include <linux/mfd/max77693-private.h>
+#endif
#if defined(CONFIG_S3C_ADC)
#include <plat/adc.h>
#endif
@@ -45,8 +49,8 @@ static char *supply_list[] = {
"battery",
};
+
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
-static bool battery_terminal_check_support(struct battery_info *info);
static void battery_error_control(struct battery_info *info);
#endif
@@ -69,7 +73,9 @@ static int battery_get_cable(struct battery_info *info)
{
union power_supply_propval value;
int cable_type = 0;
-
+#if defined(EXTENDED_ONLINE_TYPE)
+ int online_val;
+#endif
pr_debug("%s\n", __func__);
mutex_lock(&info->ops_lock);
@@ -78,7 +84,25 @@ static int battery_get_cable(struct battery_info *info)
case CABLE_DET_CHARGER:
info->psy_charger->get_property(info->psy_charger,
POWER_SUPPLY_PROP_ONLINE, &value);
+
+#if defined(EXTENDED_ONLINE_TYPE)
+ /* | 31-24: RSVD | 23-16: MAIN TYPE |
+ 15-8: SUB TYPE | 7-0: POWER TYPE | */
+ online_val = value.intval;
+ online_val &= ~(ONLINE_TYPE_RSVD_MASK);
+ cable_type = ((online_val & ONLINE_TYPE_MAIN_MASK) >>
+ ONLINE_TYPE_MAIN_SHIFT);
+ info->cable_sub_type = ((online_val & ONLINE_TYPE_SUB_MASK) >>
+ ONLINE_TYPE_SUB_SHIFT);
+ info->cable_pwr_type = ((online_val & ONLINE_TYPE_PWR_MASK) >>
+ ONLINE_TYPE_PWR_SHIFT);
+ pr_info("%s: main(%d), sub(%d), pwr(%d)\n", __func__,
+ cable_type,
+ info->cable_sub_type,
+ info->cable_pwr_type);
+#else
cable_type = value.intval;
+#endif
break;
default:
pr_err("%s: not support src(%d)\n", __func__,
@@ -172,6 +196,117 @@ static int battery_get_temper(struct battery_info *info)
return temper;
}
+#define ADC_REG_NAME "vcc_adc_1.8v"
+static int battery_set_adc_power(struct battery_info *info, bool en)
+{
+ struct regulator *regulator;
+ int is_en;
+ int ret = 0;
+ pr_debug("%s\n", __func__);
+
+ regulator = regulator_get(NULL, ADC_REG_NAME);
+ if (IS_ERR(regulator))
+ return -ENODEV;
+
+ is_en = regulator_is_enabled(regulator);
+
+ if (is_en != en)
+ pr_info("%s: %s: is_en(%d), en(%d)\n", __func__,
+ ADC_REG_NAME, is_en, en);
+
+ if (!is_en && en)
+ ret = regulator_enable(regulator);
+ else if (is_en && !en)
+ ret = regulator_force_disable(regulator);
+
+ info->adc_pwr_st = en;
+
+ regulator_put(regulator);
+
+ return ret;
+}
+
+static int battery_get_vf(struct battery_info *info)
+{
+ union power_supply_propval value;
+ int present = 0;
+ int adc;
+ pr_debug("%s\n", __func__);
+
+ if (info->factory_mode) {
+ pr_debug("%s: No need to check battery in factory mode\n",
+ __func__);
+ return 1;
+ }
+
+ mutex_lock(&info->ops_lock);
+
+ switch (info->pdata->vf_det_src) {
+ case VF_DET_ADC:
+#if defined(CONFIG_S3C_ADC)
+ if (info->pdata->vf_det_src == VF_DET_ADC)
+ battery_set_adc_power(info, 1);
+ adc = s3c_adc_read(info->adc_client, info->pdata->vf_det_ch);
+ if (info->pdata->vf_det_src == VF_DET_ADC)
+ battery_set_adc_power(info, 0);
+#else
+ adc = 350; /* temporary value */
+#endif
+ info->battery_vf_adc = adc;
+ present = INRANGE(adc, info->pdata->vf_det_th_l,
+ info->pdata->vf_det_th_h);
+ if (!present)
+ pr_info("%s: adc(%d), out of range(%d ~ %d)\n",
+ __func__, adc,
+ info->pdata->vf_det_th_l,
+ info->pdata->vf_det_th_h);
+ break;
+ case VF_DET_CHARGER:
+ info->psy_charger->get_property(info->psy_charger,
+ POWER_SUPPLY_PROP_PRESENT, &value);
+ present = value.intval;
+ break;
+ case VF_DET_GPIO:
+ present = !gpio_get_value(info->batdet_gpio);
+ break;
+ default:
+ pr_err("%s: not support src(%d)\n", __func__,
+ info->pdata->vf_det_src);
+ present = 1; /* always detected */
+ break;
+ }
+
+ pr_debug("%s: present(%d)\n", __func__, present);
+
+ mutex_unlock(&info->ops_lock);
+ return present;
+}
+
+/* judge power off or not by current_avg */
+static int battery_get_curr_avg(struct battery_info *info)
+{
+ int curr_avg;
+ pr_debug("%s\n", __func__);
+
+ /* if 0% && under min voltage && low power charging, power off */
+ if ((info->battery_soc <= PWROFF_SOC) &&
+ (info->battery_vcell < info->pdata->voltage_min) &&
+ (info->battery_v_diff < 0) &&
+ (info->input_current < info->pdata->chg_curr_ta)) {
+ pr_info("%s: soc(%d), vol(%d < %d), diff(%d), in_curr(%d)\n",
+ __func__, info->battery_soc,
+ (info->battery_vcell / 1000),
+ (info->pdata->voltage_min / 1000),
+ info->battery_v_diff,
+ info->input_current);
+ curr_avg = -1;
+ } else {
+ curr_avg = info->input_current;
+ }
+
+ return curr_avg;
+}
+
/* Get info from power supply at realtime */
int battery_get_info(struct battery_info *info,
enum power_supply_property property)
@@ -194,15 +329,15 @@ int battery_get_info(struct battery_info *info,
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_CURRENT_MAX:
case POWER_SUPPLY_PROP_CURRENT_NOW:
-#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
case POWER_SUPPLY_PROP_CHARGE_FULL:
-#endif
info->psy_charger->get_property(info->psy_charger,
property, &value);
break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ value.intval = battery_get_vf(info);
+ break;
case POWER_SUPPLY_PROP_ONLINE:
value.intval = battery_get_cable(info);
break;
@@ -212,6 +347,10 @@ int battery_get_info(struct battery_info *info,
info->psy_fuelgauge->get_property(info->psy_fuelgauge,
property, &value);
break;
+ /* Update current_avg */
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ value.intval = battery_get_curr_avg(info);
+ break;
/* Update from fuelgauge or adc */
case POWER_SUPPLY_PROP_TEMP:
value.intval = battery_get_temper(info);
@@ -230,7 +369,10 @@ void battery_update_info(struct battery_info *info)
int temper;
/* Update from Charger */
- info->cable_type = battery_get_cable(info);
+ if (info->slate_mode)
+ info->cable_type = POWER_SUPPLY_TYPE_BATTERY;
+ else
+ info->cable_type = battery_get_cable(info);
info->psy_charger->get_property(info->psy_charger,
POWER_SUPPLY_PROP_STATUS, &value);
@@ -254,9 +396,7 @@ void battery_update_info(struct battery_info *info)
info->battery_health = value.intval;
#endif
- info->psy_charger->get_property(info->psy_charger,
- POWER_SUPPLY_PROP_PRESENT, &value);
- info->battery_present = value.intval;
+ info->battery_present = battery_get_vf(info);
info->psy_charger->get_property(info->psy_charger,
POWER_SUPPLY_PROP_CURRENT_NOW, &value);
@@ -275,7 +415,7 @@ void battery_update_info(struct battery_info *info)
/* Fuelgauge power off state */
if ((info->cable_type != POWER_SUPPLY_TYPE_BATTERY) &&
- (info->battery_present == 0)) {
+ (info->battery_present == 0) && (info->monitor_count)) {
pr_info("%s: abnormal fuelgauge power state\n", __func__);
goto update_finish;
}
@@ -321,10 +461,16 @@ void battery_update_info(struct battery_info *info)
info->battery_t_delta = temper - info->battery_temper;
info->battery_temper = temper;
+ /* update current_avg later */
+ info->charge_current_avg = battery_get_curr_avg(info);
+
update_finish:
switch (info->battery_error_test) {
case 0:
pr_debug("%s: error test: not test modde\n", __func__);
+#if defined(CONFIG_TARGET_LOCALE_KOR)
+ info->errortest_stopcharging = false;
+#endif
break;
case 1:
pr_info("%s: error test: full charged\n", __func__);
@@ -346,12 +492,17 @@ update_finish:
pr_info("%s: error test: vf error\n", __func__);
info->battery_present = 0;
break;
+#if defined(CONFIG_TARGET_LOCALE_KOR)
+ case 6:
+ info->errortest_stopcharging = true;
+ break;
+#endif
default:
pr_info("%s: error test: unknown state\n", __func__);
break;
}
- pr_info("%s: state(%d), type(%d), "
+ pr_debug("%s: state(%d), type(%d), "
"health(%d), present(%d), "
"cable(%d), curr(%d), "
"soc(%d), raw(%d), "
@@ -396,22 +547,99 @@ void battery_control_info(struct battery_info *info,
}
}
-static void samsung_battery_alarm_start(struct alarm *alarm)
+static void battery_event_alarm(struct alarm *alarm)
{
struct battery_info *info = container_of(alarm, struct battery_info,
- alarm);
- pr_debug("%s\n", __func__);
+ event_alarm);
+ pr_info("%s: exit event state, %ds gone\n", __func__,
+ info->pdata->event_time);
+
+ /* clear event state */
+ info->event_state = EVENT_STATE_CLEAR;
wake_lock(&info->monitor_wake_lock);
schedule_work(&info->monitor_work);
}
+void battery_event_control(struct battery_info *info)
+{
+ int event_num;
+ ktime_t interval, next, slack;
+ /* sync with event_type in samsung_battery.h */
+ char *event_type_name[] = { "WCDMA CALL", "GSM CALL", "CALL",
+ "VIDEO", "MUSIC", "BROWSER",
+ "HOTSPOT", "CAMERA", "DATA CALL",
+ "GPS", "LTE", "WIFI",
+ "USE", "UNKNOWN"
+ };
+
+ pr_debug("%s\n", __func__);
+
+ if (info->event_type) {
+ pr_info("%s: in event state(%d), type(0x%04x)\n", __func__,
+ info->event_state, info->event_type);
+
+ for (event_num = 0; event_num < EVENT_TYPE_MAX; event_num++) {
+ if (info->event_type & (1 << event_num))
+ pr_info("%s: %d: %s\n", __func__, event_num,
+ event_type_name[event_num]);
+ }
+
+ if (info->event_state == EVENT_STATE_SET) {
+ pr_info("%s: event already set, event(%d, 0x%04x)\n",
+ __func__, info->event_state, info->event_type);
+ } else if (info->event_state == EVENT_STATE_IN_TIMER) {
+ pr_info("%s: cancel event timer\n", __func__);
+
+ alarm_cancel(&info->event_alarm);
+
+ info->event_state = EVENT_STATE_SET;
+
+ wake_lock(&info->monitor_wake_lock);
+ schedule_work(&info->monitor_work);
+ } else {
+ pr_info("%s: enter event state(%d, 0x%04x)\n",
+ __func__, info->event_state, info->event_type);
+
+ info->event_state = EVENT_STATE_SET;
+
+ wake_lock(&info->monitor_wake_lock);
+ schedule_work(&info->monitor_work);
+ }
+ } else {
+ pr_info("%s: clear event type(0x%04x), wait %ds\n", __func__,
+ info->event_type, info->pdata->event_time);
+
+ if (info->event_state == EVENT_STATE_SET) {
+ pr_info("%s: start event timer\n", __func__);
+ info->last_poll = alarm_get_elapsed_realtime();
+
+ interval = ktime_set(info->pdata->event_time, 0);
+ next = ktime_add(info->last_poll, interval);
+ slack = ktime_set(20, 0);
+
+ alarm_start_range(&info->event_alarm, next,
+ ktime_add(next, slack));
+
+ info->event_state = EVENT_STATE_IN_TIMER;
+ } else {
+ pr_info("%s: event already clear, event(%d, 0x%04x)\n",
+ __func__, info->event_state, info->event_type);
+ }
+ }
+}
+
static void battery_notify_full_state(struct battery_info *info)
{
union power_supply_propval value;
+ pr_debug("%s: r(%d), f(%d), rs(%d), fs(%d), s(%d)\n", __func__,
+ info->recharge_phase, info->full_charged_state,
+ info->battery_raw_soc, info->battery_full_soc,
+ info->battery_soc);
if ((info->recharge_phase && info->full_charged_state) ||
- ((info->battery_raw_soc > info->battery_full_soc) &&
+ ((info->charge_real_state != POWER_SUPPLY_STATUS_DISCHARGING) &&
+ (info->battery_raw_soc > info->battery_full_soc) &&
(info->battery_soc == 100))) {
/* notify full state to fuel guage */
value.intval = POWER_SUPPLY_STATUS_FULL;
@@ -420,6 +648,16 @@ static void battery_notify_full_state(struct battery_info *info)
}
}
+static void battery_monitor_alarm(struct alarm *alarm)
+{
+ struct battery_info *info = container_of(alarm, struct battery_info,
+ monitor_alarm);
+ pr_debug("%s\n", __func__);
+
+ wake_lock(&info->monitor_wake_lock);
+ schedule_work(&info->monitor_work);
+}
+
static void battery_monitor_interval(struct battery_info *info)
{
ktime_t interval, next, slack;
@@ -454,6 +692,10 @@ static void battery_monitor_interval(struct battery_info *info)
break;
}
+ /* 5 times after boot, apply no interval (1 sec) */
+ if (info->monitor_count < 5)
+ info->monitor_interval = 1;
+
/* apply monitor interval weight */
if (info->monitor_weight != 100) {
pr_info("%s: apply weight(%d), %d -> %d\n", __func__,
@@ -470,7 +712,7 @@ static void battery_monitor_interval(struct battery_info *info)
next = ktime_add(info->last_poll, interval);
slack = ktime_set(20, 0);
- alarm_start_range(&info->alarm, next, ktime_add(next, slack));
+ alarm_start_range(&info->monitor_alarm, next, ktime_add(next, slack));
local_irq_restore(flags);
}
@@ -503,8 +745,12 @@ static bool battery_abstimer_cond(struct battery_info *info)
struct timespec current_time;
pr_debug("%s\n", __func__);
+ /* always update time for info data */
+ ktime = alarm_get_elapsed_realtime();
+ info->current_time = current_time = ktime_to_timespec(ktime);
+
if ((info->cable_type == POWER_SUPPLY_TYPE_USB) ||
- (info->full_charged_state == true) ||
+ (info->full_charged_state != STATUS_NOT_FULL) ||
(info->charge_start_time == 0)) {
pr_debug("%s: not abstimer state, cb(%d), f(%d), t(%d)\n",
__func__, info->cable_type,
@@ -514,9 +760,6 @@ static bool battery_abstimer_cond(struct battery_info *info)
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 {
@@ -534,6 +777,7 @@ static bool battery_abstimer_cond(struct battery_info *info)
(int)current_time.tv_sec, info->charge_start_time,
abstimer_duration);
info->abstimer_state = true;
+ info->abstimer_active = (int)current_time.tv_sec;
} else {
pr_debug("%s: not abstimer state, t(%d - %d ?? %d)\n", __func__,
(int)current_time.tv_sec, info->charge_start_time,
@@ -548,10 +792,11 @@ static bool battery_fullcharged_cond(struct battery_info *info)
{
int f_cond_soc;
int f_cond_vcell;
+ int full_state;
pr_debug("%s\n", __func__);
- /* max voltage - 50mV */
- f_cond_vcell = info->pdata->voltage_max - 50000;
+ /* max voltage - RECHG_DROP_VALUE: recharge voltage */
+ f_cond_vcell = info->pdata->voltage_max - RECHG_DROP_VALUE;
/* max soc - 5% */
f_cond_soc = 95;
@@ -566,10 +811,32 @@ static bool battery_fullcharged_cond(struct battery_info *info)
pr_info("%s: real full charged, v(%d), s(%d)\n",
__func__, info->battery_vcell,
info->battery_soc);
- info->full_charged_state = true;
+#if defined(USE_2STEP_TERM)
+ full_state = battery_get_info(info,
+ POWER_SUPPLY_PROP_CHARGE_FULL);
+ if (!full_state) {
+ if (info->full_charged_state != STATUS_1ST_FULL)
+ pr_info("%s: 1st full by current\n",
+ __func__);
+
+ info->full_charged_state = STATUS_1ST_FULL;
+
+ return false;
+ } else {
+ if (info->full_charged_state != STATUS_2ND_FULL)
+ pr_info("%s: 2nd full by timer\n",
+ __func__);
+
+ info->full_charged_state = STATUS_2ND_FULL;
+
+ return true;
+ }
+#else
+ info->full_charged_state = STATUS_1ST_FULL;
return true;
+#endif
} else {
- pr_info("%s: charger full charged, v(%d), s(%d)\n",
+ pr_info("%s: not real full charged, v(%d), s(%d)\n",
__func__, info->battery_vcell,
info->battery_soc);
@@ -587,13 +854,13 @@ static bool battery_fullcharged_cond(struct battery_info *info)
POWER_SUPPLY_PROP_STATUS);
return false;
}
- } else if (info->full_charged_state == true) {
+ } else if (info->full_charged_state != STATUS_NOT_FULL) {
pr_debug("%s: already full charged, v(%d), s(%d)\n", __func__,
info->battery_vcell, info->battery_soc);
} else {
pr_debug("%s: not full charged, v(%d), s(%d)\n", __func__,
info->battery_vcell, info->battery_soc);
- info->full_charged_state = false;
+ info->full_charged_state = STATUS_NOT_FULL;
}
return false;
@@ -645,7 +912,6 @@ static bool battery_health_cond(struct battery_info *info)
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
if (info->cable_type == POWER_SUPPLY_TYPE_BATTERY) {
info->health_state = false;
- info->is_unspec_phase = false;
return false;
}
#endif
@@ -681,10 +947,6 @@ static bool battery_health_cond(struct battery_info *info)
info->battery_health);
info->health_state = false;
-#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
- if (battery_terminal_check_support(info))
- pr_err("%s: health support, error state!\n", __func__);
-#endif
}
return info->health_state;
@@ -692,8 +954,41 @@ static bool battery_health_cond(struct battery_info *info)
static bool battery_temper_cond(struct battery_info *info)
{
+ int ovh_stop, ovh_recover;
+ int frz_stop, frz_recover;
pr_debug("%s\n", __func__);
+ /* update overheat temperature threshold */
+ if ((info->pdata->ctia_spec == true) && (info->lpm_state)) {
+ ovh_stop = info->pdata->lpm_overheat_stop_temp;
+ ovh_recover = info->pdata->lpm_overheat_recovery_temp;
+ frz_stop = info->pdata->lpm_freeze_stop_temp;
+ frz_recover = info->pdata->lpm_freeze_recovery_temp;
+ } else if ((info->pdata->ctia_spec == true) &&
+ (info->event_state != EVENT_STATE_CLEAR)) {
+ ovh_stop = info->pdata->event_overheat_stop_temp;
+ ovh_recover = info->pdata->event_overheat_recovery_temp;
+ frz_stop = info->pdata->event_freeze_stop_temp;
+ frz_recover = info->pdata->event_freeze_recovery_temp;
+ pr_info("%s: ovh(%d/%d), frz(%d/%d), lpm(%d), "
+ "event(%d, 0x%04x)\n", __func__,
+ ovh_stop, ovh_recover, frz_stop, frz_recover,
+ info->lpm_state, info->event_state, info->event_type);
+ } else {
+ ovh_stop = info->pdata->overheat_stop_temp;
+ ovh_recover = info->pdata->overheat_recovery_temp;
+ frz_stop = info->pdata->freeze_stop_temp;
+ frz_recover = info->pdata->freeze_recovery_temp;
+ }
+
+#if defined(CONFIG_MACH_T0_USA_SPR)
+ /* unver rev0.7, do not stop charging by tempereture */
+ if (system_rev < 7) {
+ ovh_stop = info->battery_temper + 1;
+ frz_stop = info->battery_temper - 1;
+ }
+#endif
+
if (info->temper_state == false) {
if (info->charge_real_state != POWER_SUPPLY_STATUS_CHARGING) {
pr_debug("%s: r_state !charging, cs(%d)\n",
@@ -703,21 +998,15 @@ static bool battery_temper_cond(struct battery_info *info)
pr_debug("%s: check charging stop temper "
"cond: %d ?? %d ~ %d\n", __func__,
- info->battery_temper,
- info->pdata->freeze_stop_temp,
- info->pdata->overheat_stop_temp);
+ info->battery_temper, frz_stop, ovh_stop);
- if (info->battery_temper >=
- info->pdata->overheat_stop_temp) {
+ if (info->battery_temper >= ovh_stop) {
pr_info("%s: stop by overheated, t(%d ? %d)\n",
- __func__, info->battery_temper,
- info->pdata->overheat_stop_temp);
+ __func__, info->battery_temper, ovh_stop);
info->overheated_state = true;
- } else if (info->battery_temper <=
- info->pdata->freeze_stop_temp) {
- pr_info("%s: stop by overheated, t(%d ? %d)\n",
- __func__, info->battery_temper,
- info->pdata->freeze_stop_temp);
+ } else if (info->battery_temper <= frz_stop) {
+ pr_info("%s: stop by freezed, t(%d ? %d)\n",
+ __func__, info->battery_temper, frz_stop);
info->freezed_state = true;
} else
pr_debug("%s: normal charging, t(%d)\n", __func__,
@@ -725,23 +1014,17 @@ static bool battery_temper_cond(struct battery_info *info)
} else {
pr_debug("%s: check charging recovery temper "
"cond: %d ?? %d ~ %d\n", __func__,
- info->battery_temper,
- info->pdata->freeze_recovery_temp,
- info->pdata->overheat_recovery_temp);
+ info->battery_temper, frz_recover, ovh_recover);
if ((info->overheated_state == true) &&
- (info->battery_temper <=
- info->pdata->overheat_recovery_temp)) {
+ (info->battery_temper <= ovh_recover)) {
pr_info("%s: recovery from overheated, t(%d ? %d)\n",
- __func__, info->battery_temper,
- info->pdata->overheat_recovery_temp);
+ __func__, info->battery_temper, ovh_recover);
info->overheated_state = false;
} else if ((info->freezed_state == true) &&
- (info->battery_temper >=
- info->pdata->freeze_recovery_temp)) {
+ (info->battery_temper >= frz_recover)) {
pr_info("%s: recovery from freezed, t(%d ? %d)\n",
- __func__, info->battery_temper,
- info->pdata->freeze_recovery_temp);
+ __func__, info->battery_temper, frz_recover);
info->freezed_state = false;
} else
pr_info("%s: charge stopped, t(%d)\n", __func__,
@@ -781,17 +1064,38 @@ static void battery_charge_control(struct battery_info *info,
ktime = alarm_get_elapsed_realtime();
current_time = ktime_to_timespec(ktime);
- if ((chg_curr != 0) && (info->siop_state == true)) {
- pr_info("%s: siop state, charge current is %dmA\n", __func__,
- info->siop_charge_current);
- chg_curr = info->siop_charge_current;
+ if ((info->cable_type != POWER_SUPPLY_TYPE_BATTERY) &&
+ (chg_curr > 0) && (info->siop_state == true)) {
+
+ switch (info->siop_lv) {
+ case SIOP_LV1:
+ info->siop_charge_current =
+ info->pdata->chg_curr_siop_lv1;
+ break;
+ case SIOP_LV2:
+ info->siop_charge_current =
+ info->pdata->chg_curr_siop_lv2;
+ break;
+ case SIOP_LV3:
+ info->siop_charge_current =
+ info->pdata->chg_curr_siop_lv3;
+ break;
+ default:
+ info->siop_charge_current =
+ info->pdata->chg_curr_usb;
+ break;
+ }
+
+ chg_curr = MIN(chg_curr, info->siop_charge_current);
+ pr_info("%s: siop state, level(%d), cc(%d)\n",
+ __func__, info->siop_lv, chg_curr);
}
if (in_curr == KEEP_CURR)
goto charge_current_con;
/* input current limit */
- in_curr = min(in_curr, info->pdata->in_curr_limit);
+ in_curr = MIN(in_curr, info->pdata->in_curr_limit);
/* check charge input before and after */
if (info->input_current == ((in_curr / 20) * 20)) {
@@ -843,7 +1147,7 @@ charge_state_con:
battery_control_info(info, POWER_SUPPLY_PROP_STATUS, ENABLE);
info->charge_start_time = current_time.tv_sec;
- pr_err("%s: charge enabled, current as %d/%dmA @%d\n",
+ pr_info("%s: charge enabled, current as %d/%dmA @%d\n",
__func__, info->charge_current, info->input_current,
info->charge_start_time);
@@ -863,7 +1167,7 @@ charge_state_con:
} else if ((chg_curr == 0) && (info->charge_start_time != 0)) {
battery_control_info(info, POWER_SUPPLY_PROP_STATUS, DISABLE);
- pr_err("%s: charge disabled, current as %d/%dmA @%d\n",
+ pr_info("%s: charge disabled, current as %d/%dmA @%d\n",
__func__, info->charge_current, info->input_current,
(int)current_time.tv_sec);
@@ -905,13 +1209,17 @@ charge_state_con:
static void battery_indicator_icon(struct battery_info *info)
{
if (info->cable_type != POWER_SUPPLY_TYPE_BATTERY) {
- if (info->full_charged_state == true) {
+ if (info->full_charged_state != STATUS_NOT_FULL) {
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->abstimer_active) {
+ if (info->battery_soc == 100)
+ info->charge_virt_state =
+ POWER_SUPPLY_STATUS_FULL;
+ else
+ info->charge_virt_state =
+ POWER_SUPPLY_STATUS_CHARGING;
} else if (info->recharge_phase == true) {
info->charge_virt_state =
POWER_SUPPLY_STATUS_CHARGING;
@@ -1005,7 +1313,8 @@ static void battery_interval_calulation(struct battery_info *info)
}
/* prevent critical low voltage factor */
- if ((info->battery_vcell < (info->pdata->voltage_min - 100000)) ||
+ if ((info->battery_vcell <
+ (info->pdata->voltage_min - PWROFF_MARGIN)) ||
(info->battery_vfocv < info->pdata->voltage_min)) {
pr_info("%s: voltage(%d) too low state\n", __func__,
info->battery_vcell);
@@ -1053,16 +1362,16 @@ static void battery_interval_calulation(struct battery_info *info)
if (info->lpm_state == true)
info->monitor_weight *= 2;
- /* 2 times after boot(about 1min), apply charging interval(30sec) */
- if (info->monitor_count < 2) {
- pr_info("%s: now in booting, set 30s\n", __func__);
- info->monitor_mode = MONITOR_EMER_LV1;
+ /* 5 times after boot, apply no interval (1 sec) */
+ if (info->monitor_count < 5) {
+ pr_info("%s: now in booting, set 1s\n", __func__);
+ info->monitor_mode = MONITOR_EMER_LV1; /* dummy value */
return;
}
/*
* prevent low voltage phase
- * default, vcell is lower than min_voltage + 50mV, -20%
+ * default, vcell is lower than min_voltage + 50mV, -30%
*/
if (info->battery_vcell < (info->pdata->voltage_min + 50000)) {
info->monitor_mode = MONITOR_EMER_LV1;
@@ -1147,10 +1456,16 @@ static void battery_monitor_work(struct work_struct *work)
{
struct battery_info *info = container_of(work, struct battery_info,
monitor_work);
+ int muic_cb_typ;
pr_debug("%s\n", __func__);
mutex_lock(&info->mon_lock);
+ if (info->battery_test_mode) {
+ pr_info("%s: now in test mode, not updated\n", __func__);
+ goto monitor_finish;
+ }
+
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
/* first, check cable-type */
info->cable_type = battery_get_cable(info);
@@ -1163,8 +1478,9 @@ static void battery_monitor_work(struct work_struct *work)
info->overheated_state = false;
info->freezed_state = false;
info->temper_state = false;
- info->full_charged_state = false;
+ info->full_charged_state = STATUS_NOT_FULL;
info->abstimer_state = false;
+ info->abstimer_active = false;
info->recharge_phase = false;
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
@@ -1184,28 +1500,25 @@ static void battery_monitor_work(struct work_struct *work)
/* Check battery state from charger and fuelgauge */
battery_update_info(info);
-#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
- /* check unspec recovery */
- if (info->is_unspec_phase) {
- if ((info->battery_health !=
- POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) &&
- (battery_terminal_check_support(info) == false)) {
- pr_info("%s: recover from unspec phase!\n", __func__);
- info->is_unspec_recovery = true;
+ /* adc ldo , vf irq control */
+ if (info->pdata->vf_det_src == VF_DET_GPIO) {
+ if (info->cable_type == POWER_SUPPLY_TYPE_BATTERY) {
+ if (info->batdet_irq_st) {
+ disable_irq(info->batdet_irq);
+ info->batdet_irq_st = false;
+ }
+ if (info->adc_pwr_st)
+ battery_set_adc_power(info, 0);
+ } else {
+ if (!info->adc_pwr_st)
+ battery_set_adc_power(info, 1);
+ if (!info->batdet_irq_st) {
+ enable_irq(info->batdet_irq);
+ info->batdet_irq_st = true;
+ }
}
}
- /* If it's recovery phase from unspec state, go to charge_ok */
- if (info->is_unspec_recovery) {
- pr_info("%s: recovered from unspec phase"
- ": re-setting charge current!\n", __func__);
- battery_charge_control(info, OFF_CURR, OFF_CURR);
- info->is_unspec_recovery = false;
- info->is_unspec_phase = false;
- goto charge_ok;
- }
-#endif
-
/* if battery is missed state, do not check charge scenario */
if (info->battery_present == 0)
goto monitor_finish;
@@ -1215,6 +1528,14 @@ static void battery_monitor_work(struct work_struct *work)
goto charge_ok;
/* Below is charger is connected state */
+#if defined(CONFIG_TARGET_LOCALE_KOR)
+ if (info->errortest_stopcharging) {
+ pr_info("%s: charge stopped by error_test mode\n", __func__);
+ battery_charge_control(info, OFF_CURR, OFF_CURR);
+ goto monitor_finish;
+ }
+#endif
+
if (battery_temper_cond(info) == true) {
pr_info("%s: charge stopped by temperature\n", __func__);
battery_charge_control(info, OFF_CURR, OFF_CURR);
@@ -1246,7 +1567,9 @@ static void battery_monitor_work(struct work_struct *work)
}
charge_ok:
+#if defined(CONFIG_MACH_GC1)
pr_err("%s: Updated Cable State(%d)\n", __func__, info->cable_type);
+#endif
switch (info->cable_type) {
case POWER_SUPPLY_TYPE_BATTERY:
if (!info->pdata->suspend_chging)
@@ -1257,15 +1580,16 @@ charge_ok:
info->overheated_state = false;
info->freezed_state = false;
info->temper_state = false;
- info->full_charged_state = false;
+ info->full_charged_state = STATUS_NOT_FULL;
info->abstimer_state = false;
+ info->abstimer_active = 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, info->pdata->chg_curr_ta,
- info->pdata->chg_curr_ta);
+ info->pdata->in_curr_limit);
break;
case POWER_SUPPLY_TYPE_USB:
if (!info->pdata->suspend_chging)
@@ -1282,8 +1606,45 @@ charge_ok:
case POWER_SUPPLY_TYPE_DOCK:
if (!info->pdata->suspend_chging)
wake_lock(&info->charge_wake_lock);
- battery_charge_control(info, info->pdata->chg_curr_dock,
- info->pdata->chg_curr_dock);
+ muic_cb_typ = max77693_muic_get_charging_type();
+ switch (muic_cb_typ) {
+ case CABLE_TYPE_AUDIODOCK_MUIC:
+ pr_info("%s: audio dock, %d\n",
+ __func__, DOCK_TYPE_AUDIO_CURR);
+ battery_charge_control(info,
+ DOCK_TYPE_AUDIO_CURR,
+ DOCK_TYPE_AUDIO_CURR);
+ break;
+ case CABLE_TYPE_SMARTDOCK_TA_MUIC:
+ if (info->cable_sub_type == ONLINE_SUB_TYPE_SMART_OTG) {
+ pr_info("%s: smart dock ta & host, %d\n",
+ __func__, DOCK_TYPE_SMART_OTG_CURR);
+ battery_charge_control(info,
+ DOCK_TYPE_SMART_OTG_CURR,
+ DOCK_TYPE_SMART_OTG_CURR);
+ } else {
+ pr_info("%s: smart dock ta & no host, %d\n",
+ __func__, DOCK_TYPE_SMART_NOTG_CURR);
+ battery_charge_control(info,
+ DOCK_TYPE_SMART_NOTG_CURR,
+ DOCK_TYPE_SMART_NOTG_CURR);
+ }
+ break;
+ case CABLE_TYPE_SMARTDOCK_USB_MUIC:
+ pr_info("%s: smart dock usb(low), %d\n",
+ __func__, DOCK_TYPE_LOW_CURR);
+ battery_charge_control(info,
+ DOCK_TYPE_LOW_CURR,
+ DOCK_TYPE_LOW_CURR);
+ break;
+ default:
+ pr_info("%s: general dock, %d\n",
+ __func__, info->pdata->chg_curr_dock);
+ battery_charge_control(info,
+ info->pdata->chg_curr_dock,
+ info->pdata->chg_curr_dock);
+ break;
+ }
break;
case POWER_SUPPLY_TYPE_WIRELESS:
if (!info->pdata->suspend_chging)
@@ -1299,6 +1660,7 @@ monitor_finish:
/* icon indicator */
battery_indicator_icon(info);
+ /* nofify full state to fuelgauge */
battery_notify_full_state(info);
/* dynamic battery polling interval */
@@ -1311,29 +1673,48 @@ monitor_finish:
if (info->pdata->led_indicator == true)
battery_indicator_led(info);
- pr_info("[%d] bat: s(%d, %d), v(%d, %d), b(%d), "
- "t(%d.%d), h(%d), "
- "cs(%d, %d), cb(%d), cr(%d, %d), "
- "a(%d), f(%d), r(%d), t(%d)\n",
+ power_supply_changed(&info->psy_bat);
+
+ pr_info("[%d] bat: s(%d, %d), v(%d, %d), "
+ "t(%d.%d), "
+ "cs(%d, %d), cb(%d), cr(%d, %d)",
++info->monitor_count,
info->battery_soc,
info->battery_r_s_delta,
info->battery_vcell / 1000,
info->battery_v_diff / 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->input_current,
- info->abstimer_state,
- info->full_charged_state,
- info->recharge_phase,
- info->charge_start_time);
+ info->input_current);
- power_supply_changed(&info->psy_bat);
+ if (info->battery_present == 0)
+ pr_cont(", b(%d)", info->battery_present);
+ if (info->battery_health != POWER_SUPPLY_HEALTH_GOOD)
+ pr_cont(", h(%d)", info->battery_health);
+ if (info->abstimer_state == 1)
+ pr_cont(", a(%d)", info->abstimer_state);
+ if (info->abstimer_active)
+ pr_cont(", aa(%d)", info->abstimer_active);
+ if (info->full_charged_state != STATUS_NOT_FULL)
+ pr_cont(", f(%d)", info->full_charged_state);
+ if (info->recharge_phase == 1)
+ pr_cont(", r(%d)", info->recharge_phase);
+ if (info->charge_start_time != 0)
+ pr_cont(", t(%d)", ((int)info->current_time.tv_sec -
+ info->charge_start_time));
+ if (info->event_state != EVENT_STATE_CLEAR)
+ pr_cont(", e(%d, 0x%04x)", info->event_state, info->event_type);
+ if (info->siop_state)
+ pr_cont(", op(%d, %d)", info->siop_state, info->siop_lv);
+
+ pr_cont("\n");
+
+ /* check current_avg */
+ if (info->charge_current_avg < 0)
+ pr_info("%s: charging but discharging, power off\n", __func__);
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
/* prevent suspend for ui-update */
@@ -1429,35 +1810,6 @@ static void battery_error_work(struct work_struct *work)
}
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
-static bool battery_terminal_check_support(struct battery_info *info)
-{
- int full_mode;
- int vcell;
- bool ret = false;
- pr_debug("%s\n", __func__);
-
- full_mode = battery_get_info(info, POWER_SUPPLY_PROP_CHARGE_FULL);
- vcell = battery_get_info(info, POWER_SUPPLY_PROP_VOLTAGE_NOW);
- pr_debug("%s: chg_status = %d, vcell = %d\n",
- __func__, full_mode, vcell);
-
- if (full_mode && (vcell <= 3800000)) {
- pr_info("%s: top-off or done mode, but low voltage(%d)\n",
- __func__, vcell / 1000);
- /* check again */
- vcell = battery_get_info(info, POWER_SUPPLY_PROP_VOLTAGE_NOW);
- if (vcell <= 3800000) {
- pr_info("%s: top-off or done mode, but low voltage(%d), "
- "set health error!\n",
- __func__, vcell / 1000);
- info->health_state = true;
- ret = true;
- }
- }
-
- return ret;
-}
-
static void battery_error_control(struct battery_info *info)
{
pr_info("%s\n", __func__);
@@ -1478,21 +1830,12 @@ static void battery_error_control(struct battery_info *info)
POWER_SUPPLY_STATUS_NOT_CHARGING;
}
} else if (info->health_state == true) {
- if ((info->battery_health ==
- POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) ||
- battery_terminal_check_support(info)) {
- pr_info("%s: battery unspec, "
- "disable charging and off the "
- "system path!\n", __func__);
-
- /* invalid top-off state,
- assume terminals(+/-) open */
- battery_charge_control(info, OFF_CURR, OFF_CURR);
- pr_info("%s: set unspec phase!\n", __func__);
- info->is_unspec_phase = true;
- } else if (info->battery_health ==
+ if (info->battery_health ==
POWER_SUPPLY_HEALTH_OVERVOLTAGE)
pr_info("%s: vbus ovp state!", __func__);
+ else if (info->battery_health ==
+ POWER_SUPPLY_HEALTH_UNSPEC_FAILURE)
+ pr_info("%s: uspec state from charger", __func__);
}
return;
@@ -1512,7 +1855,15 @@ static enum power_supply_property samsung_battery_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+#ifdef CONFIG_SLP
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+#endif
POWER_SUPPLY_PROP_CAPACITY,
+#ifdef CONFIG_SLP
+ POWER_SUPPLY_PROP_CAPACITY_RAW,
+#endif
POWER_SUPPLY_PROP_TEMP,
};
@@ -1556,9 +1907,29 @@ static int samsung_battery_get_property(struct power_supply *ps,
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = info->charge_current;
break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = info->charge_current_avg;
+ break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = info->battery_soc;
break;
+#ifdef CONFIG_SLP
+ case POWER_SUPPLY_PROP_CAPACITY_RAW:
+ val->intval = info->battery_raw_soc;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ if (info->full_charged_state)
+ val->intval = true;
+ else
+ val->intval = false;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ if (info->charge_real_state == POWER_SUPPLY_STATUS_CHARGING)
+ val->intval = true;
+ else
+ val->intval = false;
+ break;
+#endif
case POWER_SUPPLY_PROP_TEMP:
val->intval = info->battery_temper;
break;
@@ -1590,21 +1961,59 @@ static int samsung_battery_set_property(struct power_supply *ps,
return 0;
}
- 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_MAX:
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- case POWER_SUPPLY_PROP_CAPACITY:
- case POWER_SUPPLY_PROP_TEMP:
- break;
- default:
- return -EINVAL;
+ if (info->battery_test_mode) {
+ pr_info("%s: set test value: psp(%d), val(%d)\n",
+ __func__, psp, val->intval);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ info->charge_virt_state = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ info->charge_type = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ info->battery_health = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ info->battery_present = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ info->cable_type = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ info->battery_vcell = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ info->input_current = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ info->charge_current = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ info->charge_current_avg = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ info->battery_soc = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ info->battery_temper = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ info->pdata->voltage_max = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ info->pdata->voltage_min = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ break;
+ default:
+ return -EINVAL;
+ }
}
cancel_work_sync(&info->monitor_work);
@@ -1625,8 +2034,10 @@ static int samsung_usb_get_property(struct power_supply *ps,
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);
+ val->intval = ((info->charge_virt_state !=
+ POWER_SUPPLY_STATUS_DISCHARGING) &&
+ ((info->cable_type == POWER_SUPPLY_TYPE_USB) ||
+ (info->cable_type == POWER_SUPPLY_TYPE_USB_CDP)));
return 0;
}
@@ -1642,22 +2053,48 @@ static int samsung_ac_get_property(struct power_supply *ps,
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_DOCK) ||
- (info->cable_type == POWER_SUPPLY_TYPE_WIRELESS);
+ val->intval = ((info->charge_virt_state !=
+ POWER_SUPPLY_STATUS_DISCHARGING) &&
+ ((info->cable_type == POWER_SUPPLY_TYPE_MAINS) ||
+ (info->cable_type == POWER_SUPPLY_TYPE_MISC) ||
+ (info->cable_type == POWER_SUPPLY_TYPE_DOCK) ||
+ (info->cable_type == POWER_SUPPLY_TYPE_WIRELESS)));
return 0;
}
+static irqreturn_t battery_isr(int irq, void *data)
+{
+ struct battery_info *info = data;
+ int bat_gpio;
+ pr_info("%s: irq(%d)\n", __func__, irq);
+
+ bat_gpio = gpio_get_value(info->batdet_gpio);
+ pr_info("%s: battery present gpio(%d)\n", __func__, bat_gpio);
+
+ cancel_work_sync(&info->monitor_work);
+ wake_lock(&info->monitor_wake_lock);
+ schedule_work(&info->monitor_work);
+
+ return IRQ_HANDLED;
+}
+
static __devinit int samsung_battery_probe(struct platform_device *pdev)
{
struct battery_info *info;
- int ret = 0;
+ struct samsung_battery_platform_data *pdata = pdev->dev.platform_data;
+ int ret = -ENODEV;
char *temper_src_name[] = { "fuelgauge", "ap adc",
"ext adc", "unknown"
};
- pr_info("%s: SAMSUNG Battery Driver Loading\n", __func__);
+ char *vf_src_name[] = { "adc", "charger irq", "gpio", "unknown"
+ };
+ pr_info("%s: battery init\n", __func__);
+
+ if (!pdata) {
+ pr_err("%s: no platform data\n", __func__);
+ return -ENODEV;
+ }
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
@@ -1666,7 +2103,7 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
info->dev = &pdev->dev;
- info->pdata = pdev->dev.platform_data;
+ info->pdata = pdata;
/* Check charger name and fuelgauge name. */
if (!info->pdata->charger_name || !info->pdata->fuelgauge_name) {
@@ -1699,19 +2136,37 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev)
goto err_psy_get;
}
+#if defined(CONFIG_MACH_M0)
/* WORKAROUND: set battery pdata in driver */
if (system_rev == 3) {
info->pdata->temper_src = TEMPER_EXT_ADC;
info->pdata->temper_ch = 7;
}
+#endif
pr_info("%s: Temperature source: %s\n", __func__,
temper_src_name[info->pdata->temper_src]);
+
+ /* not supported H/W rev for VF ADC */
+#if defined(CONFIG_MACH_T0) && defined(CONFIG_TARGET_LOCALE_USA)
+ if (system_rev < 7)
+ info->pdata->vf_det_src = VF_DET_CHARGER;
+#endif
+ pr_info("%s: VF detect source: %s\n", __func__,
+ vf_src_name[info->pdata->vf_det_src]);
+
/* recalculate recharge voltage, it depends on max voltage value */
info->pdata->recharge_voltage = info->pdata->voltage_max -
RECHG_DROP_VALUE;
pr_info("%s: Recharge voltage: %d\n", __func__,
info->pdata->recharge_voltage);
+
+ if (info->pdata->ctia_spec == true) {
+ pr_info("%s: applied CTIA spec, event time(%ds)\n",
+ __func__, info->pdata->event_time);
+ } else
+ pr_info("%s: not applied CTIA spec\n", __func__);
+
#if defined(CONFIG_S3C_ADC)
/* adc register */
info->adc_client = s3c_adc_register(pdev, NULL, NULL, 0);
@@ -1730,18 +2185,21 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev)
pr_info("%s: boot with charging, s(%d)\n", __func__,
info->charge_real_state);
info->charge_start_time = 1;
+ battery_set_adc_power(info, 1);
} else {
pr_info("%s: boot without charging, s(%d)\n", __func__,
info->charge_real_state);
info->charge_start_time = 0;
}
- info->full_charged_state = false;
+ info->full_charged_state = STATUS_NOT_FULL;
info->abstimer_state = false;
+ info->abstimer_active = false;
info->recharge_phase = false;
info->siop_charge_current = info->pdata->chg_curr_usb;
info->monitor_mode = MONITOR_NORM;
info->led_state = BATT_LED_DISCHARGING;
info->monitor_count = 0;
+ info->slate_mode = 0;
/* LPM charging state */
info->lpm_state = lpcharge;
@@ -1808,10 +2266,54 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev)
goto err_psy_reg_ac;
}
+ /* battery present irq */
+ if (!info->pdata->batt_present_gpio) {
+ pr_info("%s: do not support battery gpio detect\n", __func__);
+ goto gpio_bat_det_finish;
+ } else
+ pr_info("%s: support battery gpio detection\n", __func__);
+
+ info->batdet_gpio = info->pdata->batt_present_gpio;
+ info->batdet_irq = gpio_to_irq(info->batdet_gpio);
+ ret = gpio_request(info->batdet_gpio, "battery_present_n");
+ if (ret) {
+ pr_err("%s: failed requesting gpio %d\n", __func__,
+ info->batdet_gpio);
+ goto err_irq;
+ }
+ gpio_direction_input(info->batdet_gpio);
+ gpio_free(info->batdet_gpio);
+
+ ret = request_threaded_irq(info->batdet_irq, NULL,
+ battery_isr,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "batdet-irq", info);
+ if (ret) {
+ pr_err("%s: fail to request batdet irq: %d: %d\n",
+ __func__, info->batdet_irq, ret);
+ goto err_irq;
+ }
+
+ ret = enable_irq_wake(info->batdet_irq);
+ if (ret) {
+ pr_err("%s: failed enable irq wake %d\n", __func__,
+ info->batdet_irq);
+ goto err_enable_irq;
+ }
+
+ info->batdet_irq_st = true;
+gpio_bat_det_finish:
+
/* 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);
+ alarm_init(&info->monitor_alarm,
+ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+ battery_monitor_alarm);
+
+ if (info->pdata->ctia_spec == true)
+ alarm_init(&info->event_alarm,
+ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+ battery_event_alarm);
/* update battery init status */
schedule_work(&info->monitor_work);
@@ -1829,14 +2331,20 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev)
}
#endif
- pr_info("%s: SAMSUNG Battery Driver Loaded\n", __func__);
+ pr_info("%s: probe complete\n", __func__);
+
return 0;
+err_enable_irq:
+ free_irq(info->batdet_irq, info);
+err_irq:
+ power_supply_unregister(&info->psy_ac);
err_psy_reg_ac:
power_supply_unregister(&info->psy_usb);
err_psy_reg_usb:
power_supply_unregister(&info->psy_bat);
err_psy_reg_bat:
+ s3c_adc_release(info->adc_client);
wake_lock_destroy(&info->monitor_wake_lock);
wake_lock_destroy(&info->emer_wake_lock);
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
@@ -1861,6 +2369,10 @@ static int __devexit samsung_battery_remove(struct platform_device *pdev)
remove_proc_entry("battery_info_proc", NULL);
+ alarm_cancel(&info->monitor_alarm);
+ if (info->pdata->ctia_spec == true)
+ alarm_cancel(&info->event_alarm);
+
cancel_work_sync(&info->error_work);
cancel_work_sync(&info->monitor_work);
@@ -1913,6 +2425,8 @@ static void samsung_battery_complete(struct device *dev)
pr_info("%s\n", __func__);
info->monitor_mode = MONITOR_NORM;
+
+ battery_monitor_interval(info);
}
static int samsung_battery_suspend(struct device *dev)