diff options
Diffstat (limited to 'drivers/power/ab8500_fg.c')
-rw-r--r-- | drivers/power/ab8500_fg.c | 447 |
1 files changed, 319 insertions, 128 deletions
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index b3bf178c3462..25dae4c4b0ef 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -32,6 +32,7 @@ #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500/ab8500-bm.h> #include <linux/mfd/abx500/ab8500-gpadc.h> +#include <linux/kernel.h> #define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 @@ -42,7 +43,7 @@ #define NBR_AVG_SAMPLES 20 -#define LOW_BAT_CHECK_INTERVAL (2 * HZ) +#define LOW_BAT_CHECK_INTERVAL (HZ / 16) /* 62.5 ms */ #define VALID_CAPACITY_SEC (45 * 60) /* 45 minutes */ #define BATT_OK_MIN 2360 /* mV */ @@ -113,6 +114,13 @@ struct ab8500_fg_avg_cap { int sum; }; +struct ab8500_fg_cap_scaling { + bool enable; + int cap_to_scale[2]; + int disable_cap_level; + int scaled_cap; +}; + struct ab8500_fg_battery_capacity { int max_mah_design; int max_mah; @@ -123,6 +131,7 @@ struct ab8500_fg_battery_capacity { int prev_percent; int prev_level; int user_mah; + struct ab8500_fg_cap_scaling cap_scale; }; struct ab8500_fg_flags { @@ -160,6 +169,8 @@ struct inst_curr_result_list { * @recovery_cnt: Counter for recovery mode * @high_curr_cnt: Counter for high current mode * @init_cnt: Counter for init mode + * @low_bat_cnt Counter for number of consecutive low battery measures + * @nbr_cceoc_irq_cnt Counter for number of CCEOC irqs received since enabled * @recovery_needed: Indicate if recovery is needed * @high_curr_mode: Indicate if we're in high current mode * @init_capacity: Indicate if initial capacity measuring should be done @@ -167,13 +178,14 @@ struct inst_curr_result_list { * @calib_state State during offset calibration * @discharge_state: Current discharge state * @charge_state: Current charge state + * @ab8500_fg_started Completion struct used for the instant current start * @ab8500_fg_complete Completion struct used for the instant current reading * @flags: Structure for information about events triggered * @bat_cap: Structure for battery capacity specific parameters * @avg_cap: Average capacity filter * @parent: Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc - * @bat: Pointer to the abx500_bm platform data + * @bm: Platform specific battery management information * @fg_psy: Structure that holds the FG specific battery properties * @fg_wq: Work queue for running the FG algorithm * @fg_periodic_work: Work to run the FG algorithm periodically @@ -199,6 +211,8 @@ struct ab8500_fg { int recovery_cnt; int high_curr_cnt; int init_cnt; + int low_bat_cnt; + int nbr_cceoc_irq_cnt; bool recovery_needed; bool high_curr_mode; bool init_capacity; @@ -206,13 +220,14 @@ struct ab8500_fg { enum ab8500_fg_calibration_state calib_state; enum ab8500_fg_discharge_state discharge_state; enum ab8500_fg_charge_state charge_state; + struct completion ab8500_fg_started; struct completion ab8500_fg_complete; struct ab8500_fg_flags flags; struct ab8500_fg_battery_capacity bat_cap; struct ab8500_fg_avg_cap avg_cap; struct ab8500 *parent; struct ab8500_gpadc *gpadc; - struct abx500_bm_data *bat; + struct abx500_bm_data *bm; struct power_supply fg_psy; struct workqueue_struct *fg_wq; struct delayed_work fg_periodic_work; @@ -355,7 +370,7 @@ static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr) /* * We want to know if we're in low current mode */ - if (curr > -di->bat->fg_params->high_curr_threshold) + if (curr > -di->bm->fg_params->high_curr_threshold) return true; else return false; @@ -484,8 +499,9 @@ static int ab8500_fg_coulomb_counter(struct ab8500_fg *di, bool enable) di->flags.fg_enabled = true; } else { /* Clear any pending read requests */ - ret = abx500_set_register_interruptible(di->dev, - AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, 0); + ret = abx500_mask_and_set_register_interruptible(di->dev, + AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, + (RESET_ACCU | READ_REQ), 0); if (ret) goto cc_err; @@ -523,13 +539,14 @@ cc_err: * Note: This is part "one" and has to be called before * ab8500_fg_inst_curr_finalize() */ - int ab8500_fg_inst_curr_start(struct ab8500_fg *di) +int ab8500_fg_inst_curr_start(struct ab8500_fg *di) { u8 reg_val; int ret; mutex_lock(&di->cc_lock); + di->nbr_cceoc_irq_cnt = 0; ret = abx500_get_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_CC_CONF_REG, ®_val); if (ret < 0) @@ -557,6 +574,7 @@ cc_err: } /* Return and WFI */ + INIT_COMPLETION(di->ab8500_fg_started); INIT_COMPLETION(di->ab8500_fg_complete); enable_irq(di->irq); @@ -568,6 +586,17 @@ fail: } /** + * ab8500_fg_inst_curr_started() - check if fg conversion has started + * @di: pointer to the ab8500_fg structure + * + * Returns 1 if conversion started, 0 if still waiting + */ +int ab8500_fg_inst_curr_started(struct ab8500_fg *di) +{ + return completion_done(&di->ab8500_fg_started); +} + +/** * ab8500_fg_inst_curr_done() - check if fg conversion is done * @di: pointer to the ab8500_fg structure * @@ -595,13 +624,15 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) int timeout; if (!completion_done(&di->ab8500_fg_complete)) { - timeout = wait_for_completion_timeout(&di->ab8500_fg_complete, + timeout = wait_for_completion_timeout( + &di->ab8500_fg_complete, INS_CURR_TIMEOUT); dev_dbg(di->dev, "Finalize time: %d ms\n", ((INS_CURR_TIMEOUT - timeout) * 1000) / HZ); if (!timeout) { ret = -ETIME; disable_irq(di->irq); + di->nbr_cceoc_irq_cnt = 0; dev_err(di->dev, "completion timed out [%d]\n", __LINE__); goto fail; @@ -609,6 +640,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) } disable_irq(di->irq); + di->nbr_cceoc_irq_cnt = 0; ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, @@ -647,7 +679,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm */ val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) / - (1000 * di->bat->fg_res); + (1000 * di->bm->fg_res); if (di->turn_off_fg) { dev_dbg(di->dev, "%s Disable FG\n", __func__); @@ -683,6 +715,7 @@ fail: int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) { int ret; + int timeout; int res = 0; ret = ab8500_fg_inst_curr_start(di); @@ -691,13 +724,33 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) return 0; } + /* Wait for CC to actually start */ + if (!completion_done(&di->ab8500_fg_started)) { + timeout = wait_for_completion_timeout( + &di->ab8500_fg_started, + INS_CURR_TIMEOUT); + dev_dbg(di->dev, "Start time: %d ms\n", + ((INS_CURR_TIMEOUT - timeout) * 1000) / HZ); + if (!timeout) { + ret = -ETIME; + dev_err(di->dev, "completion timed out [%d]\n", + __LINE__); + goto fail; + } + } + ret = ab8500_fg_inst_curr_finalize(di, &res); if (ret) { dev_err(di->dev, "Failed to finalize fg_inst\n"); return 0; } + dev_dbg(di->dev, "%s instant current: %d", __func__, res); return res; +fail: + disable_irq(di->irq); + mutex_unlock(&di->cc_lock); + return ret; } /** @@ -750,19 +803,16 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm */ di->accu_charge = (val * QLSB_NANO_AMP_HOURS_X10) / - (100 * di->bat->fg_res); + (100 * di->bm->fg_res); /* * Convert to unit value in mA - * Full scale input voltage is - * 66.660mV => LSB = 66.660mV/(4096*res) = 1.627mA - * Given a 250ms conversion cycle time the LSB corresponds - * to 112.9 nAh. Convert to current by dividing by the conversion + * by dividing by the conversion * time in hours (= samples / (3600 * 4)h) - * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm + * and multiply with 1000 */ di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) / - (1000 * di->bat->fg_res * (di->fg_samples / 4)); + (1000 * di->bm->fg_res * (di->fg_samples / 4)); di->flags.conv_done = true; @@ -770,6 +820,8 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) queue_work(di->fg_wq, &di->fg_work); + dev_dbg(di->dev, "fg_res: %d, fg_samples: %d, gasg: %d, accu_charge: %d \n", + di->bm->fg_res, di->fg_samples, val, di->accu_charge); return; exit: dev_err(di->dev, @@ -814,8 +866,8 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) struct abx500_v_to_cap *tbl; int cap = 0; - tbl = di->bat->bat_type[di->bat->batt_id].v_to_cap_tbl, - tbl_size = di->bat->bat_type[di->bat->batt_id].n_v_cap_tbl_elements; + tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl, + tbl_size = di->bm->bat_type[di->bm->batt_id].n_v_cap_tbl_elements; for (i = 0; i < tbl_size; ++i) { if (voltage > tbl[i].voltage) @@ -866,8 +918,8 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) struct batres_vs_temp *tbl; int resist = 0; - tbl = di->bat->bat_type[di->bat->batt_id].batres_tbl; - tbl_size = di->bat->bat_type[di->bat->batt_id].n_batres_tbl_elements; + tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl; + tbl_size = di->bm->bat_type[di->bm->batt_id].n_batres_tbl_elements; for (i = 0; i < tbl_size; ++i) { if (di->bat_temp / 10 > tbl[i].temp) @@ -888,11 +940,11 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d" " fg resistance %d, total: %d (mOhm)\n", - __func__, di->bat_temp, resist, di->bat->fg_res / 10, - (di->bat->fg_res / 10) + resist); + __func__, di->bat_temp, resist, di->bm->fg_res / 10, + (di->bm->fg_res / 10) + resist); /* fg_res variable is in 0.1mOhm */ - resist += di->bat->fg_res / 10; + resist += di->bm->fg_res / 10; return resist; } @@ -915,7 +967,7 @@ static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di) do { vbat += ab8500_fg_bat_voltage(di); i++; - msleep(5); + usleep_range(5000, 6000); } while (!ab8500_fg_inst_curr_done(di)); ab8500_fg_inst_curr_finalize(di, &di->inst_curr); @@ -1108,16 +1160,16 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di) { int ret, percent; - percent = di->bat_cap.permille / 10; + percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10); - if (percent <= di->bat->cap_levels->critical || + if (percent <= di->bm->cap_levels->critical || di->flags.low_bat) ret = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; - else if (percent <= di->bat->cap_levels->low) + else if (percent <= di->bm->cap_levels->low) ret = POWER_SUPPLY_CAPACITY_LEVEL_LOW; - else if (percent <= di->bat->cap_levels->normal) + else if (percent <= di->bm->cap_levels->normal) ret = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; - else if (percent <= di->bat->cap_levels->high) + else if (percent <= di->bm->cap_levels->high) ret = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; else ret = POWER_SUPPLY_CAPACITY_LEVEL_FULL; @@ -1126,6 +1178,99 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di) } /** + * ab8500_fg_calculate_scaled_capacity() - Capacity scaling + * @di: pointer to the ab8500_fg structure + * + * Calculates the capacity to be shown to upper layers. Scales the capacity + * to have 100% as a reference from the actual capacity upon removal of charger + * when charging is in maintenance mode. + */ +static int ab8500_fg_calculate_scaled_capacity(struct ab8500_fg *di) +{ + struct ab8500_fg_cap_scaling *cs = &di->bat_cap.cap_scale; + int capacity = di->bat_cap.prev_percent; + + if (!cs->enable) + return capacity; + + /* + * As long as we are in fully charge mode scale the capacity + * to show 100%. + */ + if (di->flags.fully_charged) { + cs->cap_to_scale[0] = 100; + cs->cap_to_scale[1] = + max(capacity, di->bm->fg_params->maint_thres); + dev_dbg(di->dev, "Scale cap with %d/%d\n", + cs->cap_to_scale[0], cs->cap_to_scale[1]); + } + + /* Calculates the scaled capacity. */ + if ((cs->cap_to_scale[0] != cs->cap_to_scale[1]) + && (cs->cap_to_scale[1] > 0)) + capacity = min(100, + DIV_ROUND_CLOSEST(di->bat_cap.prev_percent * + cs->cap_to_scale[0], + cs->cap_to_scale[1])); + + if (di->flags.charging) { + if (capacity < cs->disable_cap_level) { + cs->disable_cap_level = capacity; + dev_dbg(di->dev, "Cap to stop scale lowered %d%%\n", + cs->disable_cap_level); + } else if (!di->flags.fully_charged) { + if (di->bat_cap.prev_percent >= + cs->disable_cap_level) { + dev_dbg(di->dev, "Disabling scaled capacity\n"); + cs->enable = false; + capacity = di->bat_cap.prev_percent; + } else { + dev_dbg(di->dev, + "Waiting in cap to level %d%%\n", + cs->disable_cap_level); + capacity = cs->disable_cap_level; + } + } + } + + return capacity; +} + +/** + * ab8500_fg_update_cap_scalers() - Capacity scaling + * @di: pointer to the ab8500_fg structure + * + * To be called when state change from charge<->discharge to update + * the capacity scalers. + */ +static void ab8500_fg_update_cap_scalers(struct ab8500_fg *di) +{ + struct ab8500_fg_cap_scaling *cs = &di->bat_cap.cap_scale; + + if (!cs->enable) + return; + if (di->flags.charging) { + di->bat_cap.cap_scale.disable_cap_level = + di->bat_cap.cap_scale.scaled_cap; + dev_dbg(di->dev, "Cap to stop scale at charge %d%%\n", + di->bat_cap.cap_scale.disable_cap_level); + } else { + if (cs->scaled_cap != 100) { + cs->cap_to_scale[0] = cs->scaled_cap; + cs->cap_to_scale[1] = di->bat_cap.prev_percent; + } else { + cs->cap_to_scale[0] = 100; + cs->cap_to_scale[1] = + max(di->bat_cap.prev_percent, + di->bm->fg_params->maint_thres); + } + + dev_dbg(di->dev, "Cap to scale at discharge %d/%d\n", + cs->cap_to_scale[0], cs->cap_to_scale[1]); + } +} + +/** * ab8500_fg_check_capacity_limits() - Check if capacity has changed * @di: pointer to the ab8500_fg structure * @init: capacity is allowed to go up in init mode @@ -1136,6 +1281,7 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di) static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) { bool changed = false; + int percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10); di->bat_cap.level = ab8500_fg_capacity_level(di); @@ -1167,33 +1313,41 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) dev_dbg(di->dev, "Battery low, set capacity to 0\n"); di->bat_cap.prev_percent = 0; di->bat_cap.permille = 0; + percent = 0; di->bat_cap.prev_mah = 0; di->bat_cap.mah = 0; changed = true; } else if (di->flags.fully_charged) { /* * We report 100% if algorithm reported fully charged - * unless capacity drops too much + * and show 100% during maintenance charging (scaling). */ if (di->flags.force_full) { - di->bat_cap.prev_percent = di->bat_cap.permille / 10; + di->bat_cap.prev_percent = percent; di->bat_cap.prev_mah = di->bat_cap.mah; - } else if (!di->flags.force_full && - di->bat_cap.prev_percent != - (di->bat_cap.permille) / 10 && - (di->bat_cap.permille / 10) < - di->bat->fg_params->maint_thres) { + + changed = true; + + if (!di->bat_cap.cap_scale.enable && + di->bm->capacity_scaling) { + di->bat_cap.cap_scale.enable = true; + di->bat_cap.cap_scale.cap_to_scale[0] = 100; + di->bat_cap.cap_scale.cap_to_scale[1] = + di->bat_cap.prev_percent; + di->bat_cap.cap_scale.disable_cap_level = 100; + } + } else if (di->bat_cap.prev_percent != percent) { dev_dbg(di->dev, "battery reported full " "but capacity dropping: %d\n", - di->bat_cap.permille / 10); - di->bat_cap.prev_percent = di->bat_cap.permille / 10; + percent); + di->bat_cap.prev_percent = percent; di->bat_cap.prev_mah = di->bat_cap.mah; changed = true; } - } else if (di->bat_cap.prev_percent != di->bat_cap.permille / 10) { - if (di->bat_cap.permille / 10 == 0) { + } else if (di->bat_cap.prev_percent != percent) { + if (percent == 0) { /* * We will not report 0% unless we've got * the LOW_BAT IRQ, no matter what the FG @@ -1203,11 +1357,11 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) di->bat_cap.permille = 1; di->bat_cap.prev_mah = 1; di->bat_cap.mah = 1; + percent = 1; changed = true; } else if (!(!di->flags.charging && - (di->bat_cap.permille / 10) > - di->bat_cap.prev_percent) || init) { + percent > di->bat_cap.prev_percent) || init) { /* * We do not allow reported capacity to go up * unless we're charging or if we're in init @@ -1215,9 +1369,9 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) dev_dbg(di->dev, "capacity changed from %d to %d (%d)\n", di->bat_cap.prev_percent, - di->bat_cap.permille / 10, + percent, di->bat_cap.permille); - di->bat_cap.prev_percent = di->bat_cap.permille / 10; + di->bat_cap.prev_percent = percent; di->bat_cap.prev_mah = di->bat_cap.mah; changed = true; @@ -1225,12 +1379,20 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) dev_dbg(di->dev, "capacity not allowed to go up since " "no charger is connected: %d to %d (%d)\n", di->bat_cap.prev_percent, - di->bat_cap.permille / 10, + percent, di->bat_cap.permille); } } if (changed) { + if (di->bm->capacity_scaling) { + di->bat_cap.cap_scale.scaled_cap = + ab8500_fg_calculate_scaled_capacity(di); + + dev_info(di->dev, "capacity=%d (%d)\n", + di->bat_cap.prev_percent, + di->bat_cap.cap_scale.scaled_cap); + } power_supply_changed(&di->fg_psy); if (di->flags.fully_charged && di->flags.force_full) { dev_dbg(di->dev, "Battery full, notifying.\n"); @@ -1284,7 +1446,7 @@ static void ab8500_fg_algorithm_charging(struct ab8500_fg *di) switch (di->charge_state) { case AB8500_FG_CHARGE_INIT: di->fg_samples = SEC_TO_SAMPLE( - di->bat->fg_params->accu_charging); + di->bm->fg_params->accu_charging); ab8500_fg_coulomb_counter(di, true); ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_READOUT); @@ -1296,7 +1458,7 @@ static void ab8500_fg_algorithm_charging(struct ab8500_fg *di) * Read the FG and calculate the new capacity */ mutex_lock(&di->cc_lock); - if (!di->flags.conv_done) { + if (!di->flags.conv_done && !di->flags.force_full) { /* Wasn't the CC IRQ that got us here */ mutex_unlock(&di->cc_lock); dev_dbg(di->dev, "%s CC conv not done\n", @@ -1346,8 +1508,8 @@ static bool check_sysfs_capacity(struct ab8500_fg *di) cap_permille = ab8500_fg_convert_mah_to_permille(di, di->bat_cap.user_mah); - lower = di->bat_cap.permille - di->bat->fg_params->user_cap_limit * 10; - upper = di->bat_cap.permille + di->bat->fg_params->user_cap_limit * 10; + lower = di->bat_cap.permille - di->bm->fg_params->user_cap_limit * 10; + upper = di->bat_cap.permille + di->bm->fg_params->user_cap_limit * 10; if (lower < 0) lower = 0; @@ -1387,7 +1549,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) case AB8500_FG_DISCHARGE_INIT: /* We use the FG IRQ to work on */ di->init_cnt = 0; - di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer); + di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer); ab8500_fg_coulomb_counter(di, true); ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INITMEASURING); @@ -1400,18 +1562,17 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) * samples to get an initial capacity. * Then go to READOUT */ - sleep_time = di->bat->fg_params->init_timer; + sleep_time = di->bm->fg_params->init_timer; /* Discard the first [x] seconds */ - if (di->init_cnt > - di->bat->fg_params->init_discard_time) { + if (di->init_cnt > di->bm->fg_params->init_discard_time) { ab8500_fg_calc_cap_discharge_voltage(di, true); ab8500_fg_check_capacity_limits(di, true); } di->init_cnt += sleep_time; - if (di->init_cnt > di->bat->fg_params->init_total_time) + if (di->init_cnt > di->bm->fg_params->init_total_time) ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_READOUT_INIT); @@ -1426,7 +1587,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) /* Intentional fallthrough */ case AB8500_FG_DISCHARGE_RECOVERY: - sleep_time = di->bat->fg_params->recovery_sleep_timer; + sleep_time = di->bm->fg_params->recovery_sleep_timer; /* * We should check the power consumption @@ -1438,9 +1599,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) if (ab8500_fg_is_low_curr(di, di->inst_curr)) { if (di->recovery_cnt > - di->bat->fg_params->recovery_total_time) { + di->bm->fg_params->recovery_total_time) { di->fg_samples = SEC_TO_SAMPLE( - di->bat->fg_params->accu_high_curr); + di->bm->fg_params->accu_high_curr); ab8500_fg_coulomb_counter(di, true); ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_READOUT); @@ -1453,7 +1614,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) di->recovery_cnt += sleep_time; } else { di->fg_samples = SEC_TO_SAMPLE( - di->bat->fg_params->accu_high_curr); + di->bm->fg_params->accu_high_curr); ab8500_fg_coulomb_counter(di, true); ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_READOUT); @@ -1462,7 +1623,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) case AB8500_FG_DISCHARGE_READOUT_INIT: di->fg_samples = SEC_TO_SAMPLE( - di->bat->fg_params->accu_high_curr); + di->bm->fg_params->accu_high_curr); ab8500_fg_coulomb_counter(di, true); ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_READOUT); @@ -1480,7 +1641,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) if (di->recovery_needed) { ab8500_fg_discharge_state_to(di, - AB8500_FG_DISCHARGE_RECOVERY); + AB8500_FG_DISCHARGE_INIT_RECOVERY); queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0); @@ -1509,9 +1670,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) } di->high_curr_cnt += - di->bat->fg_params->accu_high_curr; + di->bm->fg_params->accu_high_curr; if (di->high_curr_cnt > - di->bat->fg_params->high_curr_time) + di->bm->fg_params->high_curr_time) di->recovery_needed = true; ab8500_fg_calc_cap_discharge_fg(di); @@ -1523,12 +1684,10 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) case AB8500_FG_DISCHARGE_WAKEUP: ab8500_fg_coulomb_counter(di, true); - di->inst_curr = ab8500_fg_inst_curr_blocking(di); - ab8500_fg_calc_cap_discharge_voltage(di, true); di->fg_samples = SEC_TO_SAMPLE( - di->bat->fg_params->accu_high_curr); + di->bm->fg_params->accu_high_curr); ab8500_fg_coulomb_counter(di, true); ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_READOUT); @@ -1641,8 +1800,6 @@ static void ab8500_fg_periodic_work(struct work_struct *work) fg_periodic_work.work); if (di->init_capacity) { - /* A dummy read that will return 0 */ - di->inst_curr = ab8500_fg_inst_curr_blocking(di); /* Get an initial capacity calculation */ ab8500_fg_calc_cap_discharge_voltage(di, true); ab8500_fg_check_capacity_limits(di, true); @@ -1684,24 +1841,26 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work) * If we have had a battery over-voltage situation, * check ovv-bit to see if it should be reset. */ - if (di->flags.bat_ovv) { - ret = abx500_get_register_interruptible(di->dev, - AB8500_CHARGER, AB8500_CH_STAT_REG, - ®_value); - if (ret < 0) { - dev_err(di->dev, "%s ab8500 read failed\n", __func__); - return; - } - if ((reg_value & BATT_OVV) != BATT_OVV) { - dev_dbg(di->dev, "Battery recovered from OVV\n"); - di->flags.bat_ovv = false; + ret = abx500_get_register_interruptible(di->dev, + AB8500_CHARGER, AB8500_CH_STAT_REG, + ®_value); + if (ret < 0) { + dev_err(di->dev, "%s ab8500 read failed\n", __func__); + return; + } + if ((reg_value & BATT_OVV) == BATT_OVV) { + if (!di->flags.bat_ovv) { + dev_dbg(di->dev, "Battery OVV\n"); + di->flags.bat_ovv = true; power_supply_changed(&di->fg_psy); - return; } - /* Not yet recovered from ovv, reschedule this test */ queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work, - round_jiffies(HZ)); + HZ); + } else { + dev_dbg(di->dev, "Battery recovered from OVV\n"); + di->flags.bat_ovv = false; + power_supply_changed(&di->fg_psy); } } @@ -1721,26 +1880,30 @@ static void ab8500_fg_low_bat_work(struct work_struct *work) vbat = ab8500_fg_bat_voltage(di); /* Check if LOW_BAT still fulfilled */ - if (vbat < di->bat->fg_params->lowbat_threshold) { - di->flags.low_bat = true; - dev_warn(di->dev, "Battery voltage still LOW\n"); - - /* - * We need to re-schedule this check to be able to detect - * if the voltage increases again during charging - */ - queue_delayed_work(di->fg_wq, &di->fg_low_bat_work, - round_jiffies(LOW_BAT_CHECK_INTERVAL)); + if (vbat < di->bm->fg_params->lowbat_threshold) { + /* Is it time to shut down? */ + if (di->low_bat_cnt < 1) { + di->flags.low_bat = true; + dev_warn(di->dev, "Shut down pending...\n"); + } else { + /* + * Else we need to re-schedule this check to be able to detect + * if the voltage increases again during charging or + * due to decreasing load. + */ + di->low_bat_cnt--; + dev_warn(di->dev, "Battery voltage still LOW\n"); + queue_delayed_work(di->fg_wq, &di->fg_low_bat_work, + round_jiffies(LOW_BAT_CHECK_INTERVAL)); + } } else { - di->flags.low_bat = false; + di->flags.low_bat_delay = false; + di->low_bat_cnt = 10; dev_warn(di->dev, "Battery voltage OK again\n"); } /* This is needed to dispatch LOW_BAT */ ab8500_fg_check_capacity_limits(di, false); - - /* Set this flag to check if LOW_BAT IRQ still occurs */ - di->flags.low_bat_delay = false; } /** @@ -1779,8 +1942,8 @@ static int ab8500_fg_battok_init_hw_register(struct ab8500_fg *di) int ret; int new_val; - sel0 = di->bat->fg_params->battok_falling_th_sel0; - sel1 = di->bat->fg_params->battok_raising_th_sel1; + sel0 = di->bm->fg_params->battok_falling_th_sel0; + sel1 = di->bm->fg_params->battok_raising_th_sel1; cbp_sel0 = ab8500_fg_battok_calc(di, sel0); cbp_sel1 = ab8500_fg_battok_calc(di, sel1); @@ -1828,7 +1991,13 @@ static void ab8500_fg_instant_work(struct work_struct *work) static irqreturn_t ab8500_fg_cc_data_end_handler(int irq, void *_di) { struct ab8500_fg *di = _di; - complete(&di->ab8500_fg_complete); + if (!di->nbr_cceoc_irq_cnt) { + di->nbr_cceoc_irq_cnt++; + complete(&di->ab8500_fg_started); + } else { + di->nbr_cceoc_irq_cnt = 0; + complete(&di->ab8500_fg_complete); + } return IRQ_HANDLED; } @@ -1875,8 +2044,6 @@ static irqreturn_t ab8500_fg_batt_ovv_handler(int irq, void *_di) struct ab8500_fg *di = _di; dev_dbg(di->dev, "Battery OVV\n"); - di->flags.bat_ovv = true; - power_supply_changed(&di->fg_psy); /* Schedule a new HW failure check */ queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work, 0); @@ -1895,6 +2062,7 @@ static irqreturn_t ab8500_fg_lowbatf_handler(int irq, void *_di) { struct ab8500_fg *di = _di; + /* Initiate handling in ab8500_fg_low_bat_work() if not already initiated. */ if (!di->flags.low_bat_delay) { dev_warn(di->dev, "Battery voltage is below LOW threshold\n"); di->flags.low_bat_delay = true; @@ -1963,7 +2131,7 @@ static int ab8500_fg_get_property(struct power_supply *psy, di->bat_cap.max_mah); break; case POWER_SUPPLY_PROP_ENERGY_NOW: - if (di->flags.batt_unknown && !di->bat->chg_unknown_bat && + if (di->flags.batt_unknown && !di->bm->chg_unknown_bat && di->flags.batt_id_received) val->intval = ab8500_fg_convert_mah_to_uwh(di, di->bat_cap.max_mah); @@ -1978,21 +2146,23 @@ static int ab8500_fg_get_property(struct power_supply *psy, val->intval = di->bat_cap.max_mah; break; case POWER_SUPPLY_PROP_CHARGE_NOW: - if (di->flags.batt_unknown && !di->bat->chg_unknown_bat && + if (di->flags.batt_unknown && !di->bm->chg_unknown_bat && di->flags.batt_id_received) val->intval = di->bat_cap.max_mah; else val->intval = di->bat_cap.prev_mah; break; case POWER_SUPPLY_PROP_CAPACITY: - if (di->flags.batt_unknown && !di->bat->chg_unknown_bat && + if (di->bm->capacity_scaling) + val->intval = di->bat_cap.cap_scale.scaled_cap; + else if (di->flags.batt_unknown && !di->bm->chg_unknown_bat && di->flags.batt_id_received) val->intval = 100; else val->intval = di->bat_cap.prev_percent; break; case POWER_SUPPLY_PROP_CAPACITY_LEVEL: - if (di->flags.batt_unknown && !di->bat->chg_unknown_bat && + if (di->flags.batt_unknown && !di->bm->chg_unknown_bat && di->flags.batt_id_received) val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; else @@ -2049,6 +2219,8 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) break; di->flags.charging = false; di->flags.fully_charged = false; + if (di->bm->capacity_scaling) + ab8500_fg_update_cap_scalers(di); queue_work(di->fg_wq, &di->fg_work); break; case POWER_SUPPLY_STATUS_FULL: @@ -2061,10 +2233,13 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) queue_work(di->fg_wq, &di->fg_work); break; case POWER_SUPPLY_STATUS_CHARGING: - if (di->flags.charging) + if (di->flags.charging && + !di->flags.fully_charged) break; di->flags.charging = true; di->flags.fully_charged = false; + if (di->bm->capacity_scaling) + ab8500_fg_update_cap_scalers(di); queue_work(di->fg_wq, &di->fg_work); break; }; @@ -2075,10 +2250,11 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_TECHNOLOGY: switch (ext->type) { case POWER_SUPPLY_TYPE_BATTERY: - if (!di->flags.batt_id_received) { + if (!di->flags.batt_id_received && + di->bm->batt_id != BATTERY_UNKNOWN) { const struct abx500_battery_type *b; - b = &(di->bat->bat_type[di->bat->batt_id]); + b = &(di->bm->bat_type[di->bm->batt_id]); di->flags.batt_id_received = true; @@ -2104,8 +2280,8 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_TEMP: switch (ext->type) { case POWER_SUPPLY_TYPE_BATTERY: - if (di->flags.batt_id_received) - di->bat_temp = ret.intval; + if (di->flags.batt_id_received) + di->bat_temp = ret.intval; break; default: break; @@ -2155,7 +2331,7 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di) AB8500_SYS_CTRL2_BLOCK, AB8500_LOW_BAT_REG, ab8500_volt_to_regval( - di->bat->fg_params->lowbat_threshold) << 1 | + di->bm->fg_params->lowbat_threshold) << 1 | LOW_BAT_ENABLE); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); @@ -2395,6 +2571,11 @@ static int ab8500_fg_suspend(struct platform_device *pdev, struct ab8500_fg *di = platform_get_drvdata(pdev); flush_delayed_work(&di->fg_periodic_work); + flush_work(&di->fg_work); + flush_work(&di->fg_acc_cur_work); + flush_delayed_work(&di->fg_reinit_work); + flush_delayed_work(&di->fg_low_bat_work); + flush_delayed_work(&di->fg_check_hw_failure_work); /* * If the FG is enabled we will disable it before going to suspend @@ -2448,6 +2629,7 @@ static char *supply_interface[] = { static int ab8500_fg_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct abx500_bm_data *plat = pdev->dev.platform_data; struct ab8500_fg *di; int i, irq; int ret = 0; @@ -2457,21 +2639,19 @@ static int ab8500_fg_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__); return -ENOMEM; } - di->bat = pdev->mfd_cell->platform_data; - if (!di->bat) { - if (np) { - ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); - if (ret) { - dev_err(&pdev->dev, - "failed to get battery information\n"); - return ret; - } - } else { - dev_err(&pdev->dev, "missing dt node for ab8500_fg\n"); - return -EINVAL; + + if (!plat) { + dev_err(&pdev->dev, "no battery management data supplied\n"); + return -EINVAL; + } + di->bm = plat; + + if (np) { + ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); + if (ret) { + dev_err(&pdev->dev, "failed to get battery information\n"); + return ret; } - } else { - dev_info(&pdev->dev, "falling back to legacy platform data\n"); } mutex_init(&di->cc_lock); @@ -2491,11 +2671,11 @@ static int ab8500_fg_probe(struct platform_device *pdev) di->fg_psy.external_power_changed = ab8500_fg_external_power_changed; di->bat_cap.max_mah_design = MILLI_TO_MICRO * - di->bat->bat_type[di->bat->batt_id].charge_full_design; + di->bm->bat_type[di->bm->batt_id].charge_full_design; di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom = di->bat->bat_type[di->bat->batt_id].nominal_voltage; + di->vbat_nom = di->bm->bat_type[di->bm->batt_id].nominal_voltage; di->init_capacity = true; @@ -2531,6 +2711,12 @@ static int ab8500_fg_probe(struct platform_device *pdev) INIT_DEFERRABLE_WORK(&di->fg_check_hw_failure_work, ab8500_fg_check_hw_failure_work); + /* Reset battery low voltage flag */ + di->flags.low_bat = false; + + /* Initialize low battery counter */ + di->low_bat_cnt = 10; + /* Initialize OVV, and other registers */ ret = ab8500_fg_init_hw_registers(di); if (ret) { @@ -2549,10 +2735,14 @@ static int ab8500_fg_probe(struct platform_device *pdev) goto free_inst_curr_wq; } - di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer); + di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer); ab8500_fg_coulomb_counter(di, true); - /* Initialize completion used to notify completion of inst current */ + /* + * Initialize completion used to notify completion and start + * of inst current + */ + init_completion(&di->ab8500_fg_started); init_completion(&di->ab8500_fg_complete); /* Register interrupts */ @@ -2572,6 +2762,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) } di->irq = platform_get_irq_byname(pdev, "CCEOC"); disable_irq(di->irq); + di->nbr_cceoc_irq_cnt = 0; platform_set_drvdata(pdev, di); |