summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/supply/ab8500-bm.h14
-rw-r--r--drivers/power/supply/ab8500_bmdata.c27
-rw-r--r--drivers/power/supply/ab8500_chargalg.c41
-rw-r--r--drivers/power/supply/power_supply_core.c11
4 files changed, 62 insertions, 31 deletions
diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h
index 6efd5174dbce..4d74d21cf1eb 100644
--- a/drivers/power/supply/ab8500-bm.h
+++ b/drivers/power/supply/ab8500-bm.h
@@ -331,24 +331,12 @@ struct ab8500_maxim_parameters {
* struct ab8500_battery_type - different batteries supported
* @resis_high: battery upper resistance limit
* @resis_low: battery lower resistance limit
- * @maint_a_cur_lvl: charger current in maintenance A state in mA
- * @maint_a_vol_lvl: charger voltage in maintenance A state in mV
- * @maint_a_chg_timer_h: charge time in maintenance A state
- * @maint_b_cur_lvl: charger current in maintenance B state in mA
- * @maint_b_vol_lvl: charger voltage in maintenance B state in mV
- * @maint_b_chg_timer_h: charge time in maintenance B state
* @low_high_cur_lvl: charger current in temp low/high state in mA
* @low_high_vol_lvl: charger voltage in temp low/high state in mV'
*/
struct ab8500_battery_type {
int resis_high;
int resis_low;
- int maint_a_cur_lvl;
- int maint_a_vol_lvl;
- int maint_a_chg_timer_h;
- int maint_b_cur_lvl;
- int maint_b_vol_lvl;
- int maint_b_chg_timer_h;
int low_high_cur_lvl;
int low_high_vol_lvl;
};
@@ -393,7 +381,6 @@ struct ab8500_bm_charger_parameters {
* @usb_safety_tmr_h safety timer for usb charger
* @bkup_bat_v voltage which we charge the backup battery with
* @bkup_bat_i current which we charge the backup battery with
- * @no_maintenance indicates that maintenance charging is disabled
* @capacity_scaling indicates whether capacity scaling is to be used
* @chg_unknown_bat flag to enable charging of unknown batteries
* @enable_overshoot flag to enable VBAT overshoot control
@@ -417,7 +404,6 @@ struct ab8500_bm_data {
int usb_safety_tmr_h;
int bkup_bat_v;
int bkup_bat_i;
- bool no_maintenance;
bool capacity_scaling;
bool chg_unknown_bat;
bool enable_overshoot;
diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c
index d8fc72be0f0e..66a454942c7c 100644
--- a/drivers/power/supply/ab8500_bmdata.c
+++ b/drivers/power/supply/ab8500_bmdata.c
@@ -58,16 +58,25 @@ static struct power_supply_resistance_temp_table temp_to_batres_tbl_thermistor[]
{ .temp = -20, .resistance = 198 /* 595 mOhm */ },
};
+static struct power_supply_maintenance_charge_table ab8500_maint_charg_table[] = {
+ {
+ /* Maintenance charging phase A, 60 hours */
+ .charge_current_max_ua = 400000,
+ .charge_voltage_max_uv = 4050000,
+ .charge_safety_timer_minutes = 60*60,
+ },
+ {
+ /* Maintenance charging phase B, 200 hours */
+ .charge_current_max_ua = 400000,
+ .charge_voltage_max_uv = 4000000,
+ .charge_safety_timer_minutes = 200*60,
+ }
+};
+
/* Default battery type for reference designs is the unknown type */
static struct ab8500_battery_type bat_type_thermistor_unknown = {
.resis_high = 0,
.resis_low = 0,
- .maint_a_cur_lvl = 400,
- .maint_a_vol_lvl = 4050,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 400,
- .maint_b_vol_lvl = 4000,
- .maint_b_chg_timer_h = 200,
.low_high_cur_lvl = 300,
.low_high_vol_lvl = 4000,
};
@@ -124,7 +133,6 @@ struct ab8500_bm_data ab8500_bm_data = {
.usb_safety_tmr_h = 4,
.bkup_bat_v = BUP_VCH_SEL_2P6V,
.bkup_bat_i = BUP_ICH_SEL_150UA,
- .no_maintenance = false,
.capacity_scaling = false,
.chg_unknown_bat = false,
.enable_overshoot = false,
@@ -179,6 +187,11 @@ int ab8500_bm_of_probe(struct power_supply *psy,
/* Charging stops when we drop below this current */
bi->charge_term_current_ua = 200000;
+ if (!bi->maintenance_charge || !bi->maintenance_charge_size) {
+ bi->maintenance_charge = ab8500_maint_charg_table;
+ bi->maintenance_charge_size = ARRAY_SIZE(ab8500_maint_charg_table);
+ }
+
/*
* Internal resistance and factory resistance are tightly coupled
* so both MUST be defined or we fall back to defaults.
diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c
index b5a3096e78a1..6054996b6260 100644
--- a/drivers/power/supply/ab8500_chargalg.c
+++ b/drivers/power/supply/ab8500_chargalg.c
@@ -430,7 +430,7 @@ static void ab8500_chargalg_stop_safety_timer(struct ab8500_chargalg *di)
/**
* ab8500_chargalg_start_maintenance_timer() - Start charging maintenance timer
* @di: pointer to the ab8500_chargalg structure
- * @duration: duration of ther maintenance timer in hours
+ * @duration: duration of ther maintenance timer in minutes
*
* The maintenance timer is used to maintain the charge in the battery once
* the battery is considered full. These timers are chosen to match the
@@ -439,9 +439,10 @@ static void ab8500_chargalg_stop_safety_timer(struct ab8500_chargalg *di)
static void ab8500_chargalg_start_maintenance_timer(struct ab8500_chargalg *di,
int duration)
{
+ /* Set a timer in minutes with a 30 second range */
hrtimer_set_expires_range(&di->maintenance_timer,
- ktime_set(duration * ONE_HOUR_IN_SECONDS, 0),
- ktime_set(FIVE_MINUTES_IN_SECONDS, 0));
+ ktime_set(duration * 60, 0),
+ ktime_set(30, 0));
di->events.maintenance_timer_expired = false;
hrtimer_start_expires(&di->maintenance_timer, HRTIMER_MODE_REL);
}
@@ -1223,6 +1224,7 @@ static void ab8500_chargalg_external_power_changed(struct power_supply *psy)
static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
{
struct power_supply_battery_info *bi = di->bm->bi;
+ struct power_supply_maintenance_charge_table *mt;
int charger_status;
int ret;
@@ -1433,7 +1435,12 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
handle_maxim_chg_curr(di);
if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
di->maintenance_chg) {
- if (di->bm->no_maintenance)
+ /*
+ * The battery is fully charged, check if we support
+ * maintenance charging else go back to waiting for
+ * the recharge voltage limit.
+ */
+ if (!power_supply_supports_maintenance_charging(bi))
ab8500_chargalg_state_to(di,
STATE_WAIT_FOR_RECHARGE_INIT);
else
@@ -1454,12 +1461,19 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
break;
case STATE_MAINTENANCE_A_INIT:
+ mt = power_supply_get_maintenance_charging_setting(bi, 0);
+ if (!mt) {
+ /* No maintenance A state, go back to normal */
+ ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
+ power_supply_changed(di->chargalg_psy);
+ break;
+ }
ab8500_chargalg_stop_safety_timer(di);
ab8500_chargalg_start_maintenance_timer(di,
- di->bm->bat_type->maint_a_chg_timer_h);
+ mt->charge_safety_timer_minutes);
ab8500_chargalg_start_charging(di,
- di->bm->bat_type->maint_a_vol_lvl,
- di->bm->bat_type->maint_a_cur_lvl);
+ mt->charge_voltage_max_uv,
+ mt->charge_current_max_ua);
ab8500_chargalg_state_to(di, STATE_MAINTENANCE_A);
power_supply_changed(di->chargalg_psy);
fallthrough;
@@ -1472,11 +1486,18 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
break;
case STATE_MAINTENANCE_B_INIT:
+ mt = power_supply_get_maintenance_charging_setting(bi, 1);
+ if (!mt) {
+ /* No maintenance B state, go back to normal */
+ ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
+ power_supply_changed(di->chargalg_psy);
+ break;
+ }
ab8500_chargalg_start_maintenance_timer(di,
- di->bm->bat_type->maint_b_chg_timer_h);
+ mt->charge_safety_timer_minutes);
ab8500_chargalg_start_charging(di,
- di->bm->bat_type->maint_b_vol_lvl,
- di->bm->bat_type->maint_b_cur_lvl);
+ mt->charge_voltage_max_uv,
+ mt->charge_current_max_ua);
ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B);
power_supply_changed(di->chargalg_psy);
fallthrough;
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 8dbd1197cc62..accbbd36bfe7 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -595,6 +595,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
info->precharge_voltage_max_uv = -EINVAL;
info->charge_restart_voltage_uv = -EINVAL;
info->overvoltage_limit_uv = -EINVAL;
+ info->maintenance_charge = NULL;
info->temp_ambient_alert_min = INT_MIN;
info->temp_ambient_alert_max = INT_MAX;
info->temp_alert_min = INT_MIN;
@@ -844,6 +845,16 @@ int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *t
}
EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple);
+struct power_supply_maintenance_charge_table *
+power_supply_get_maintenance_charging_setting(struct power_supply_battery_info *info,
+ int index)
+{
+ if (index >= info->maintenance_charge_size)
+ return NULL;
+ return &info->maintenance_charge[index];
+}
+EXPORT_SYMBOL_GPL(power_supply_get_maintenance_charging_setting);
+
/**
* power_supply_ocv2cap_simple() - find the battery capacity
* @table: Pointer to battery OCV lookup table