From e32ad07cea1f198db1cc6c2055dd8471b562a535 Mon Sep 17 00:00:00 2001 From: Kalle Komierowski Date: Thu, 2 Feb 2012 16:05:46 +0100 Subject: ab8500_fg: Don't clear the CCMuxOffset bit The CCMuxOffset bit is not kept set. This will force the columb counter of the AB8500 to use the measure offset calibration. This should increase the accuracy of the fuel gauge. Signed-off-by: Kalle Komierowski Signed-off-by: Marcus Cooper Signed-off-by: Lee Jones Reviewed-by: Jonas ABERG --- drivers/power/ab8500_fg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index ed62ef788eb5..5a9f58d4c0fb 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -484,8 +484,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; @@ -1403,8 +1404,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) sleep_time = di->bat->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->bat->fg_params->init_discard_time) { ab8500_fg_calc_cap_discharge_voltage(di, true); ab8500_fg_check_capacity_limits(di, true); -- cgit v1.2.3 From b0284de05e07d56ff7de154d0c9263788755f5eb Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 30 Nov 2012 10:09:42 +0000 Subject: ab8500_bm: Rename battery management platform data to something more logical The platform specific battery management configuration data structure is currently called 'bat' short for 'battery'; however, it contains information for all components of the battery management group, rather than information pertaining to the battery itself - there are other structures for that. So, in keeping with its structure namesake 'abx500_bm_data', we rename it to 'bm' here. Using similar logic, we're also renaming 'bmdevs_of_probe' to the more device specific 'ab8500_bm_of_probe'. Signed-off-by: Lee Jones --- drivers/power/ab8500_bmdata.c | 6 +-- drivers/power/ab8500_btemp.c | 60 ++++++++++----------- drivers/power/ab8500_charger.c | 24 ++++----- drivers/power/ab8500_fg.c | 96 +++++++++++++++++----------------- drivers/power/abx500_chargalg.c | 112 ++++++++++++++++++++-------------------- include/linux/mfd/abx500.h | 6 +-- 6 files changed, 152 insertions(+), 152 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c index df5a590d760e..c2fb2c554019 100644 --- a/drivers/power/ab8500_bmdata.c +++ b/drivers/power/ab8500_bmdata.c @@ -452,9 +452,9 @@ struct abx500_bm_data ab8500_bm_data = { .fg_params = &fg, }; -int __devinit bmdevs_of_probe(struct device *dev, - struct device_node *np, - struct abx500_bm_data **battery) +int __devinit ab8500_bm_of_probe(struct device *dev, + struct device_node *np, + struct abx500_bm_data **battery) { struct batres_vs_temp *tmp_batres_tbl; struct device_node *np_bat_supply; diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 5d1bf0bd6fa5..33ed0fccbd0e 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -78,7 +78,7 @@ struct ab8500_btemp_ranges { * @parent: Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @fg: Pointer to the struct fg - * @bat: Pointer to the abx500_bm platform data + * @bm: Platform specific battery management information * @btemp_psy: Structure for BTEMP specific battery properties * @events: Structure for information about events triggered * @btemp_ranges: Battery temperature range structure @@ -95,7 +95,7 @@ struct ab8500_btemp { struct ab8500 *parent; struct ab8500_gpadc *gpadc; struct ab8500_fg *fg; - struct abx500_bm_data *bat; + struct abx500_bm_data *bm; struct power_supply btemp_psy; struct ab8500_btemp_events events; struct ab8500_btemp_ranges btemp_ranges; @@ -149,13 +149,13 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di, return (450000 * (v_batctrl)) / (1800 - v_batctrl); } - if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL) { + if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) { /* * If the battery has internal NTC, we use the current * source to calculate the resistance, 7uA or 20uA */ rbs = (v_batctrl * 1000 - - di->bat->gnd_lift_resistance * inst_curr) + - di->bm->gnd_lift_resistance * inst_curr) / di->curr_source; } else { /* @@ -211,7 +211,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, return 0; /* Only do this for batteries with internal NTC */ - if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) { + if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) { if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA) curr = BAT_CTRL_7U_ENA; else @@ -243,7 +243,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, __func__); goto disable_curr_source; } - } else if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) { + } else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) { dev_dbg(di->dev, "Disable BATCTRL curr source\n"); /* Write 0 to the curr bits */ @@ -459,9 +459,9 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) int rbat, rntc, vntc; u8 id; - id = di->bat->batt_id; + id = di->bm->batt_id; - if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && + if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && id != BATTERY_UNKNOWN) { rbat = ab8500_btemp_get_batctrl_res(di); @@ -476,8 +476,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) } temp = ab8500_btemp_res_to_temp(di, - di->bat->bat_type[id].r_to_t_tbl, - di->bat->bat_type[id].n_temp_tbl_elements, rbat); + di->bm->bat_type[id].r_to_t_tbl, + di->bm->bat_type[id].n_temp_tbl_elements, rbat); } else { vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL); if (vntc < 0) { @@ -493,8 +493,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) rntc = 230000 * vntc / (VTVOUT_V - vntc); temp = ab8500_btemp_res_to_temp(di, - di->bat->bat_type[id].r_to_t_tbl, - di->bat->bat_type[id].n_temp_tbl_elements, rntc); + di->bm->bat_type[id].r_to_t_tbl, + di->bm->bat_type[id].n_temp_tbl_elements, rntc); prev = temp; } dev_dbg(di->dev, "Battery temperature is %d\n", temp); @@ -515,7 +515,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) u8 i; di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA; - di->bat->batt_id = BATTERY_UNKNOWN; + di->bm->batt_id = BATTERY_UNKNOWN; res = ab8500_btemp_get_batctrl_res(di); if (res < 0) { @@ -524,23 +524,23 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) } /* BATTERY_UNKNOWN is defined on position 0, skip it! */ - for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) { - if ((res <= di->bat->bat_type[i].resis_high) && - (res >= di->bat->bat_type[i].resis_low)) { + for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) { + if ((res <= di->bm->bat_type[i].resis_high) && + (res >= di->bm->bat_type[i].resis_low)) { dev_dbg(di->dev, "Battery detected on %s" " low %d < res %d < high: %d" " index: %d\n", - di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL ? + di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL ? "BATCTRL" : "BATTEMP", - di->bat->bat_type[i].resis_low, res, - di->bat->bat_type[i].resis_high, i); + di->bm->bat_type[i].resis_low, res, + di->bm->bat_type[i].resis_high, i); - di->bat->batt_id = i; + di->bm->batt_id = i; break; } } - if (di->bat->batt_id == BATTERY_UNKNOWN) { + if (di->bm->batt_id == BATTERY_UNKNOWN) { dev_warn(di->dev, "Battery identified as unknown" ", resistance %d Ohm\n", res); return -ENXIO; @@ -550,13 +550,13 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) * We only have to change current source if the * detected type is Type 1, else we use the 7uA source */ - if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && - di->bat->batt_id == 1) { + if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && + di->bm->batt_id == 1) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; } - return di->bat->batt_id; + return di->bm->batt_id; } /** @@ -586,9 +586,9 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) } if (di->events.ac_conn || di->events.usb_conn) - interval = di->bat->temp_interval_chg; + interval = di->bm->temp_interval_chg; else - interval = di->bat->temp_interval_nochg; + interval = di->bm->temp_interval_nochg; /* Schedule a new measurement */ queue_delayed_work(di->btemp_wq, @@ -815,7 +815,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = di->bat->bat_type[di->bat->batt_id].name; + val->intval = di->bm->bat_type[di->bm->batt_id].name; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); @@ -985,10 +985,10 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__); return -ENOMEM; } - di->bat = pdev->mfd_cell->platform_data; - if (!di->bat) { + di->bm = pdev->mfd_cell->platform_data; + if (!di->bm) { if (np) { - ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); + ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index d27dd7fec163..21dc8422778d 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -189,7 +189,7 @@ struct ab8500_charger_usb_state { * @autopower_cfg platform specific power config support for "pwron after pwrloss" * @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 * @flags: Structure for information about events triggered * @usb_state: Structure for usb stack information * @ac_chg: AC charger power supply @@ -226,7 +226,7 @@ struct ab8500_charger { bool autopower_cfg; struct ab8500 *parent; struct ab8500_gpadc *gpadc; - struct abx500_bm_data *bat; + struct abx500_bm_data *bm; struct ab8500_charger_event_flags flags; struct ab8500_charger_usb_state usb_state; struct ux500_charger ac_chg; @@ -1034,7 +1034,7 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, int min_value; /* We should always use to lowest current limit */ - min_value = min(di->bat->chg_params->usb_curr_max, ich_in); + min_value = min(di->bm->chg_params->usb_curr_max, ich_in); switch (min_value) { case 100: @@ -1176,7 +1176,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, volt_index = ab8500_voltage_to_regval(vset); curr_index = ab8500_current_to_regval(iset); input_curr_index = ab8500_current_to_regval( - di->bat->chg_params->ac_curr_max); + di->bm->chg_params->ac_curr_max); if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { dev_err(di->dev, "Charger voltage or current too high, " @@ -1193,7 +1193,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* MainChInputCurr: current that can be drawn from the charger*/ ret = ab8500_charger_set_main_in_curr(di, - di->bat->chg_params->ac_curr_max); + di->bm->chg_params->ac_curr_max); if (ret) { dev_err(di->dev, "%s Failed to set MainChInputCurr\n", __func__); @@ -1209,7 +1209,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* Check if VBAT overshoot control should be enabled */ - if (!di->bat->enable_overshoot) + if (!di->bm->enable_overshoot) overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N; /* Enable Main Charger */ @@ -1376,7 +1376,7 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, return ret; } /* Check if VBAT overshoot control should be enabled */ - if (!di->bat->enable_overshoot) + if (!di->bm->enable_overshoot) overshoot = USB_CHG_NO_OVERSHOOT_ENA_N; /* Enable USB Charger */ @@ -2454,8 +2454,8 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_BACKUP_CHG_REG, - di->bat->bkup_bat_v | - di->bat->bkup_bat_i); + di->bm->bkup_bat_v | + di->bm->bkup_bat_i); if (ret) { dev_err(di->dev, "failed to setup backup battery charging\n"); goto out; @@ -2644,10 +2644,10 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__); return -ENOMEM; } - di->bat = pdev->mfd_cell->platform_data; - if (!di->bat) { + di->bm = pdev->mfd_cell->platform_data; + if (!di->bm) { if (np) { - ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); + ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 5a9f58d4c0fb..4cf231375de3 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -173,7 +173,7 @@ struct inst_curr_result_list { * @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 @@ -212,7 +212,7 @@ struct ab8500_fg { 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 +355,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; @@ -648,7 +648,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__); @@ -751,7 +751,7 @@ 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 @@ -763,7 +763,7 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm */ 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; @@ -815,8 +815,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) @@ -867,8 +867,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) @@ -889,11 +889,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; } @@ -1111,14 +1111,14 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di) percent = 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; @@ -1183,7 +1183,7 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) di->bat_cap.prev_percent != (di->bat_cap.permille) / 10 && (di->bat_cap.permille / 10) < - di->bat->fg_params->maint_thres) { + di->bm->fg_params->maint_thres) { dev_dbg(di->dev, "battery reported full " "but capacity dropping: %d\n", @@ -1285,7 +1285,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); @@ -1347,8 +1347,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; @@ -1388,7 +1388,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); @@ -1401,17 +1401,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 +1426,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 +1438,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 +1453,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 +1462,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); @@ -1509,9 +1509,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); @@ -1528,7 +1528,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *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); @@ -1721,7 +1721,7 @@ 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) { + if (vbat < di->bm->fg_params->lowbat_threshold) { di->flags.low_bat = true; dev_warn(di->dev, "Battery voltage still LOW\n"); @@ -1779,8 +1779,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); @@ -1963,7 +1963,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 +1978,21 @@ 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->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 @@ -2078,7 +2078,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) if (!di->flags.batt_id_received) { 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; @@ -2155,7 +2155,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__); @@ -2457,10 +2457,10 @@ static int __devinit 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) { + di->bm = pdev->mfd_cell->platform_data; + if (!di->bm) { if (np) { - ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); + ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); @@ -2491,11 +2491,11 @@ static int __devinit 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; @@ -2549,7 +2549,7 @@ static int __devinit 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 */ diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index dcdc4393b9e7..ea2e2eb652ef 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -207,7 +207,7 @@ enum maxim_ret { * @chg_info: information about connected charger types * @batt_data: data of the battery * @susp_status: current charger suspension status - * @bat: pointer to the abx500_bm platform data + * @bm: Platform specific battery management information * @chargalg_psy: structure that holds the battery properties exposed by * the charging algorithm * @events: structure for information about events triggered @@ -232,7 +232,7 @@ struct abx500_chargalg { struct abx500_chargalg_charger_info chg_info; struct abx500_chargalg_battery_data batt_data; struct abx500_chargalg_suspension_status susp_status; - struct abx500_bm_data *bat; + struct abx500_bm_data *bm; struct power_supply chargalg_psy; struct ux500_charger *ac_chg; struct ux500_charger *usb_chg; @@ -367,13 +367,13 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di) case AC_CHG: timer_expiration = round_jiffies(jiffies + - (di->bat->main_safety_tmr_h * 3600 * HZ)); + (di->bm->main_safety_tmr_h * 3600 * HZ)); break; case USB_CHG: timer_expiration = round_jiffies(jiffies + - (di->bat->usb_safety_tmr_h * 3600 * HZ)); + (di->bm->usb_safety_tmr_h * 3600 * HZ)); break; default: @@ -638,32 +638,32 @@ static void abx500_chargalg_start_charging(struct abx500_chargalg *di, */ static void abx500_chargalg_check_temp(struct abx500_chargalg *di) { - if (di->batt_data.temp > (di->bat->temp_low + di->t_hyst_norm) && - di->batt_data.temp < (di->bat->temp_high - di->t_hyst_norm)) { + if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) && + di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) { /* Temp OK! */ di->events.btemp_underover = false; di->events.btemp_lowhigh = false; di->t_hyst_norm = 0; di->t_hyst_lowhigh = 0; } else { - if (((di->batt_data.temp >= di->bat->temp_high) && + if (((di->batt_data.temp >= di->bm->temp_high) && (di->batt_data.temp < - (di->bat->temp_over - di->t_hyst_lowhigh))) || + (di->bm->temp_over - di->t_hyst_lowhigh))) || ((di->batt_data.temp > - (di->bat->temp_under + di->t_hyst_lowhigh)) && - (di->batt_data.temp <= di->bat->temp_low))) { + (di->bm->temp_under + di->t_hyst_lowhigh)) && + (di->batt_data.temp <= di->bm->temp_low))) { /* TEMP minor!!!!! */ di->events.btemp_underover = false; di->events.btemp_lowhigh = true; - di->t_hyst_norm = di->bat->temp_hysteresis; + di->t_hyst_norm = di->bm->temp_hysteresis; di->t_hyst_lowhigh = 0; - } else if (di->batt_data.temp <= di->bat->temp_under || - di->batt_data.temp >= di->bat->temp_over) { + } else if (di->batt_data.temp <= di->bm->temp_under || + di->batt_data.temp >= di->bm->temp_over) { /* TEMP major!!!!! */ di->events.btemp_underover = true; di->events.btemp_lowhigh = false; di->t_hyst_norm = 0; - di->t_hyst_lowhigh = di->bat->temp_hysteresis; + di->t_hyst_lowhigh = di->bm->temp_hysteresis; } else { /* Within hysteresis */ dev_dbg(di->dev, "Within hysteresis limit temp: %d " @@ -682,12 +682,12 @@ static void abx500_chargalg_check_temp(struct abx500_chargalg *di) */ static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di) { - if (di->chg_info.usb_volt > di->bat->chg_params->usb_volt_max) + if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max) di->chg_info.usb_chg_ok = false; else di->chg_info.usb_chg_ok = true; - if (di->chg_info.ac_volt > di->bat->chg_params->ac_volt_max) + if (di->chg_info.ac_volt > di->bm->chg_params->ac_volt_max) di->chg_info.ac_chg_ok = false; else di->chg_info.ac_chg_ok = true; @@ -707,10 +707,10 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di) if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && di->charge_state == STATE_NORMAL && !di->maintenance_chg && (di->batt_data.volt >= - di->bat->bat_type[di->bat->batt_id].termination_vol || + di->bm->bat_type[di->bm->batt_id].termination_vol || di->events.usb_cv_active || di->events.ac_cv_active) && di->batt_data.avg_curr < - di->bat->bat_type[di->bat->batt_id].termination_curr && + di->bm->bat_type[di->bm->batt_id].termination_curr && di->batt_data.avg_curr > 0) { if (++di->eoc_cnt >= EOC_COND_CNT) { di->eoc_cnt = 0; @@ -733,12 +733,12 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di) static void init_maxim_chg_curr(struct abx500_chargalg *di) { di->ccm.original_iset = - di->bat->bat_type[di->bat->batt_id].normal_cur_lvl; + di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; di->ccm.current_iset = - di->bat->bat_type[di->bat->batt_id].normal_cur_lvl; - di->ccm.test_delta_i = di->bat->maxi->charger_curr_step; - di->ccm.max_current = di->bat->maxi->chg_curr; - di->ccm.condition_cnt = di->bat->maxi->wait_cycles; + di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; + di->ccm.test_delta_i = di->bm->maxi->charger_curr_step; + di->ccm.max_current = di->bm->maxi->chg_curr; + di->ccm.condition_cnt = di->bm->maxi->wait_cycles; di->ccm.level = 0; } @@ -755,7 +755,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) { int delta_i; - if (!di->bat->maxi->ena_maxi) + if (!di->bm->maxi->ena_maxi) return MAXIM_RET_NOACTION; delta_i = di->ccm.original_iset - di->batt_data.inst_curr; @@ -766,7 +766,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) if (di->ccm.wait_cnt == 0) { dev_dbg(di->dev, "lowering current\n"); di->ccm.wait_cnt++; - di->ccm.condition_cnt = di->bat->maxi->wait_cycles; + di->ccm.condition_cnt = di->bm->maxi->wait_cycles; di->ccm.max_current = di->ccm.current_iset - di->ccm.test_delta_i; di->ccm.current_iset = di->ccm.max_current; @@ -791,7 +791,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) if (di->ccm.current_iset == di->ccm.original_iset) return MAXIM_RET_NOACTION; - di->ccm.condition_cnt = di->bat->maxi->wait_cycles; + di->ccm.condition_cnt = di->bm->maxi->wait_cycles; di->ccm.current_iset = di->ccm.original_iset; di->ccm.level = 0; @@ -803,7 +803,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) di->ccm.max_current) { if (di->ccm.condition_cnt-- == 0) { /* Increse the iset with cco.test_delta_i */ - di->ccm.condition_cnt = di->bat->maxi->wait_cycles; + di->ccm.condition_cnt = di->bm->maxi->wait_cycles; di->ccm.current_iset += di->ccm.test_delta_i; di->ccm.level++; dev_dbg(di->dev, " Maximization needed, increase" @@ -818,7 +818,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) return MAXIM_RET_NOACTION; } } else { - di->ccm.condition_cnt = di->bat->maxi->wait_cycles; + di->ccm.condition_cnt = di->bm->maxi->wait_cycles; return MAXIM_RET_NOACTION; } } @@ -838,7 +838,7 @@ static void handle_maxim_chg_curr(struct abx500_chargalg *di) break; case MAXIM_RET_IBAT_TOO_HIGH: result = abx500_chargalg_update_chg_curr(di, - di->bat->bat_type[di->bat->batt_id].normal_cur_lvl); + di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; @@ -1210,7 +1210,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) * this way */ if (!charger_status || - (di->events.batt_unknown && !di->bat->chg_unknown_bat)) { + (di->events.batt_unknown && !di->bm->chg_unknown_bat)) { if (di->charge_state != STATE_HANDHELD) { di->events.safety_timer_expired = false; abx500_chargalg_state_to(di, STATE_HANDHELD_INIT); @@ -1394,8 +1394,8 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_NORMAL_INIT: abx500_chargalg_start_charging(di, - di->bat->bat_type[di->bat->batt_id].normal_vol_lvl, - di->bat->bat_type[di->bat->batt_id].normal_cur_lvl); + di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, + di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); abx500_chargalg_state_to(di, STATE_NORMAL); abx500_chargalg_start_safety_timer(di); abx500_chargalg_stop_maintenance_timer(di); @@ -1411,7 +1411,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) handle_maxim_chg_curr(di); if (di->charge_status == POWER_SUPPLY_STATUS_FULL && di->maintenance_chg) { - if (di->bat->no_maintenance) + if (di->bm->no_maintenance) abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE_INIT); else @@ -1429,7 +1429,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_WAIT_FOR_RECHARGE: if (di->batt_data.volt <= - di->bat->bat_type[di->bat->batt_id].recharge_vol) { + di->bm->bat_type[di->bm->batt_id].recharge_vol) { if (di->rch_cnt-- == 0) abx500_chargalg_state_to(di, STATE_NORMAL_INIT); } else @@ -1439,13 +1439,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_MAINTENANCE_A_INIT: abx500_chargalg_stop_safety_timer(di); abx500_chargalg_start_maintenance_timer(di, - di->bat->bat_type[ - di->bat->batt_id].maint_a_chg_timer_h); + di->bm->bat_type[ + di->bm->batt_id].maint_a_chg_timer_h); abx500_chargalg_start_charging(di, - di->bat->bat_type[ - di->bat->batt_id].maint_a_vol_lvl, - di->bat->bat_type[ - di->bat->batt_id].maint_a_cur_lvl); + di->bm->bat_type[ + di->bm->batt_id].maint_a_vol_lvl, + di->bm->bat_type[ + di->bm->batt_id].maint_a_cur_lvl); abx500_chargalg_state_to(di, STATE_MAINTENANCE_A); power_supply_changed(&di->chargalg_psy); /* Intentional fallthrough*/ @@ -1459,13 +1459,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_MAINTENANCE_B_INIT: abx500_chargalg_start_maintenance_timer(di, - di->bat->bat_type[ - di->bat->batt_id].maint_b_chg_timer_h); + di->bm->bat_type[ + di->bm->batt_id].maint_b_chg_timer_h); abx500_chargalg_start_charging(di, - di->bat->bat_type[ - di->bat->batt_id].maint_b_vol_lvl, - di->bat->bat_type[ - di->bat->batt_id].maint_b_cur_lvl); + di->bm->bat_type[ + di->bm->batt_id].maint_b_vol_lvl, + di->bm->bat_type[ + di->bm->batt_id].maint_b_cur_lvl); abx500_chargalg_state_to(di, STATE_MAINTENANCE_B); power_supply_changed(&di->chargalg_psy); /* Intentional fallthrough*/ @@ -1479,10 +1479,10 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_TEMP_LOWHIGH_INIT: abx500_chargalg_start_charging(di, - di->bat->bat_type[ - di->bat->batt_id].low_high_vol_lvl, - di->bat->bat_type[ - di->bat->batt_id].low_high_cur_lvl); + di->bm->bat_type[ + di->bm->batt_id].low_high_vol_lvl, + di->bm->bat_type[ + di->bm->batt_id].low_high_cur_lvl); abx500_chargalg_stop_maintenance_timer(di); di->charge_status = POWER_SUPPLY_STATUS_CHARGING; abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH); @@ -1543,11 +1543,11 @@ static void abx500_chargalg_periodic_work(struct work_struct *work) if (di->chg_info.conn_chg) queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, - di->bat->interval_charging * HZ); + di->bm->interval_charging * HZ); else queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, - di->bat->interval_not_charging * HZ); + di->bm->interval_not_charging * HZ); } /** @@ -1614,7 +1614,7 @@ static int abx500_chargalg_get_property(struct power_supply *psy, if (di->events.batt_ovv) { val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } else if (di->events.btemp_underover) { - if (di->batt_data.temp <= di->bat->temp_under) + if (di->batt_data.temp <= di->bm->temp_under) val->intval = POWER_SUPPLY_HEALTH_COLD; else val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; @@ -1814,10 +1814,10 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__); return -ENOMEM; } - di->bat = pdev->mfd_cell->platform_data; - if (!di->bat) { + di->bm = pdev->mfd_cell->platform_data; + if (!di->bm) { if (np) { - ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); + ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 2138bd33021a..6ce749a0e9d4 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -279,9 +279,9 @@ enum { NTC_INTERNAL, }; -int bmdevs_of_probe(struct device *dev, - struct device_node *np, - struct abx500_bm_data **battery); +int ab8500_bm_of_probe(struct device *dev, + struct device_node *np, + struct abx500_bm_data **battery); int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg, u8 value); -- cgit v1.2.3 From 23a04f9f40f2b32ee593b768483105b1c776814d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 29 Nov 2012 15:08:41 +0000 Subject: ab8500_bm: Always send platform specific battery information via pdata Currently the AB8500 battery management subsystem receives platform specific information via two different means depending on how the platform is booted. If DT is not enabled, a reference to a *_bm_data data structure containing each platform specific attribute is passed though platform_data. However, if DT is enabled, then platform_data is empty and the reference is gained though a DT specific probe function. There are two issues here 1) the same reference is being collected each time and 2) the DT way doesn't allow any provisions to select different platform specific attributes, which kind of defeats the object. Cc: Samuel Ortiz Signed-off-by: Lee Jones --- drivers/mfd/ab8500-core.c | 8 -------- drivers/power/ab8500_bmdata.c | 33 ++++++++++++++------------------- drivers/power/ab8500_btemp.c | 2 +- drivers/power/ab8500_charger.c | 2 +- drivers/power/ab8500_fg.c | 2 +- drivers/power/abx500_chargalg.c | 2 +- include/linux/mfd/abx500.h | 2 +- 7 files changed, 19 insertions(+), 32 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 5ec70f26b9d5..bbd49d796902 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1044,40 +1044,32 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = { .of_compatible = "stericsson,ab8500-charger", .num_resources = ARRAY_SIZE(ab8500_charger_resources), .resources = ab8500_charger_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, { .name = "ab8500-btemp", .of_compatible = "stericsson,ab8500-btemp", .num_resources = ARRAY_SIZE(ab8500_btemp_resources), .resources = ab8500_btemp_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, { .name = "ab8500-fg", .of_compatible = "stericsson,ab8500-fg", .num_resources = ARRAY_SIZE(ab8500_fg_resources), .resources = ab8500_fg_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, { .name = "ab8500-chargalg", .of_compatible = "stericsson,ab8500-chargalg", .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), .resources = ab8500_chargalg_resources, -#ifndef CONFIG_OF .platform_data = &ab8500_bm_data, .pdata_size = sizeof(ab8500_bm_data), -#endif }, }; diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c index c2fb2c554019..6b772e5f515f 100644 --- a/drivers/power/ab8500_bmdata.c +++ b/drivers/power/ab8500_bmdata.c @@ -454,16 +454,13 @@ struct abx500_bm_data ab8500_bm_data = { int __devinit ab8500_bm_of_probe(struct device *dev, struct device_node *np, - struct abx500_bm_data **battery) + struct abx500_bm_data *bm) { struct batres_vs_temp *tmp_batres_tbl; struct device_node *np_bat_supply; - struct abx500_bm_data *bat; const char *btech; int i; - *battery = &ab8500_bm_data; - /* get phandle to 'battery-info' node */ np_bat_supply = of_parse_phandle(np, "battery", 0); if (!np_bat_supply) { @@ -477,16 +474,14 @@ int __devinit ab8500_bm_of_probe(struct device *dev, return -EINVAL; } - bat = *battery; - if (strncmp(btech, "LION", 4) == 0) { - bat->no_maintenance = true; - bat->chg_unknown_bat = true; - bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; - bat->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; - bat->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130; - bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; - bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; + bm->no_maintenance = true; + bm->chg_unknown_bat = true; + bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; + bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; + bm->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130; + bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; + bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; } if (of_property_read_bool(np_bat_supply, "thermistor-on-batctrl")) { @@ -495,15 +490,15 @@ int __devinit ab8500_bm_of_probe(struct device *dev, else tmp_batres_tbl = temp_to_batres_tbl_thermistor; } else { - bat->n_btypes = 4; - bat->bat_type = bat_type_ext_thermistor; - bat->adc_therm = ABx500_ADC_THERM_BATTEMP; - tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor; + bm->n_btypes = 4; + bm->bat_type = bat_type_ext_thermistor; + bm->adc_therm = ABx500_ADC_THERM_BATTEMP; + tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor; } /* select the battery resolution table */ - for (i = 0; i < bat->n_btypes; ++i) - bat->bat_type[i]->batres_tbl = tmp_batres_tbl; + for (i = 0; i < bm->n_btypes; ++i) + bm->bat_type[i].batres_tbl = tmp_batres_tbl; of_node_put(np_bat_supply); diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 33ed0fccbd0e..c0f7dcceae45 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -988,7 +988,7 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di->bm = pdev->mfd_cell->platform_data; if (!di->bm) { if (np) { - ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); + ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 21dc8422778d..c1077df26783 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2647,7 +2647,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) di->bm = pdev->mfd_cell->platform_data; if (!di->bm) { if (np) { - ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); + ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 4cf231375de3..8bb9df92627d 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2460,7 +2460,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di->bm = pdev->mfd_cell->platform_data; if (!di->bm) { if (np) { - ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); + ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index ea2e2eb652ef..22a511c2a719 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1817,7 +1817,7 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev) di->bm = pdev->mfd_cell->platform_data; if (!di->bm) { if (np) { - ret = ab8500_bm_of_probe(&pdev->dev, np, &di->bm); + ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); if (ret) { dev_err(&pdev->dev, "failed to get battery information\n"); diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 6ce749a0e9d4..4906b1842d2f 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -281,7 +281,7 @@ enum { int ab8500_bm_of_probe(struct device *dev, struct device_node *np, - struct abx500_bm_data **battery); + struct abx500_bm_data *bm); int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg, u8 value); -- cgit v1.2.3 From 195c1c660c1868ac2024ad0ee3d5dce49bde4488 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 30 Nov 2012 10:56:51 +0000 Subject: ab8500_fg: Reorder obtainment of platform specific battery management data Now that we always pass platform specific battery management data through platform_data instead of obtaining it via different means depending the way be boot the system (DT or ATAGs); we need to re-jiggle the way we acquire it in the driver start-up functions. Now it is wrong for it to be missing, but we still allow Device Tree code to fiddle with it once we've confirmed it's there. Signed-off-by: Lee Jones --- drivers/power/ab8500_fg.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 8bb9df92627d..df681a80d8a4 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2448,6 +2448,7 @@ static char *supply_interface[] = { static int __devinit 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 +2458,19 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__); return -ENOMEM; } - di->bm = pdev->mfd_cell->platform_data; - if (!di->bm) { - 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_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); -- cgit v1.2.3 From 3988a4df3499e604a3f2ae979372d27fc5664f77 Mon Sep 17 00:00:00 2001 From: Johan Bjornstedt Date: Fri, 11 Jan 2013 13:12:50 +0000 Subject: ab8500_bm: Skip first CCEOC irq for instant current When enabling the CCEOC irq we might get false interrupt from ab8500-driver due to the latched value will be saved and interpreted as an IRQ when enabled Signed-off-by: Lee Jones Signed-off-by: Johan Bjornstedt Signed-off-by: Henrik Solver Reviewed-by: Karl KOMIEROWSKI Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_btemp.c | 11 +++---- drivers/power/ab8500_fg.c | 63 +++++++++++++++++++++++++++++++----- include/linux/mfd/abx500/ab8500-bm.h | 7 ++++ 3 files changed, 66 insertions(+), 15 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index e1d28039ce7b..4a570b6c9e47 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -374,13 +374,10 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di) return ret; } - /* - * Since there is no interrupt when current measurement is done, - * loop for over 250ms (250ms is one sample conversion time - * with 32.768 Khz RTC clock). Note that a stop time must be set - * since the ab8500_btemp_read_batctrl_voltage call can block and - * take an unknown amount of time to complete. - */ + do { + msleep(20); + } while (!ab8500_fg_inst_curr_started(di->fg)); + i = 0; do { diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 3d05c73813c8..0f40c968286c 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -160,6 +160,7 @@ 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 + * @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,6 +168,7 @@ 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 @@ -199,6 +201,7 @@ struct ab8500_fg { int recovery_cnt; int high_curr_cnt; int init_cnt; + int nbr_cceoc_irq_cnt; bool recovery_needed; bool high_curr_mode; bool init_capacity; @@ -206,6 +209,7 @@ 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; @@ -524,13 +528,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) @@ -558,6 +563,7 @@ cc_err: } /* Return and WFI */ + INIT_COMPLETION(di->ab8500_fg_started); INIT_COMPLETION(di->ab8500_fg_complete); enable_irq(di->irq); @@ -568,6 +574,17 @@ fail: return ret; } +/** + * 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 @@ -596,13 +613,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; @@ -610,6 +629,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, @@ -684,6 +704,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); @@ -692,13 +713,32 @@ 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: + mutex_unlock(&di->cc_lock); + return ret; } /** @@ -1523,8 +1563,6 @@ 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( @@ -1641,8 +1679,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); @@ -1828,7 +1864,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; } @@ -2551,7 +2593,11 @@ static int ab8500_fg_probe(struct platform_device *pdev) 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 */ @@ -2571,6 +2617,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); diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h index 44310c98ee6e..6c6a02e53cd9 100644 --- a/include/linux/mfd/abx500/ab8500-bm.h +++ b/include/linux/mfd/abx500/ab8500-bm.h @@ -431,11 +431,18 @@ struct ab8500_fg *ab8500_fg_get(void); int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev); int ab8500_fg_inst_curr_start(struct ab8500_fg *di); int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res); +int ab8500_fg_inst_curr_started(struct ab8500_fg *di); int ab8500_fg_inst_curr_done(struct ab8500_fg *di); #else +int ab8500_fg_inst_curr_started(struct ab8500_fg *di) +{ + return 0; +} + int ab8500_fg_inst_curr_done(struct ab8500_fg *di) { + return 0; } static void ab8500_fg_reinit(void) { -- cgit v1.2.3 From 9a0bd070fd3582aed024a2f13a30b1de307db1e2 Mon Sep 17 00:00:00 2001 From: Jonas Aaberg Date: Tue, 15 Jan 2013 14:09:13 +0000 Subject: ab8500_fg: Replace msleep() with usleep_range() for greater accuracy Doing so provides a greater degree of accuracy when dealing with time-frames between 1us and 20ms. msleep() is only accurate for wake-ups greater than 20ms. Signed-off-by: Lee Jones Signed-off-by: Jonas ABERG Reviewed-by: Johan BJORNSTEDT Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_fg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 0f40c968286c..f3dbba8b3925 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -956,7 +956,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); -- cgit v1.2.3 From ea4024017831d61874351defe8f8c58ae73f8009 Mon Sep 17 00:00:00 2001 From: Marcus Cooper Date: Fri, 11 Jan 2013 13:12:54 +0000 Subject: ab8500_bm: Recharge condition not optimal for battery Today the battery recharge is determined with a voltage threshold. This voltage threshold is only valid when the battery is relaxed. In charging algorithm the voltage read is the loaded battery voltage and no compensation is done to get the relaxed voltage. When maintenance charging is not selected, this makes the recharging condition to almost immediately activate when there is a discharge present on the battery. Depending on which vendor the battery comes from this behavior can wear out the battery much faster than normal. The fuelgauge driver is responsible to monitor the actual battery capacity and is able to estimate the remaining capacity. It is better to use the remaining capacity as a limit to determine when battery should be recharged. Signed-off-by: Lee Jones Signed-off-by: Marcus Cooper Reviewed-by: Hakan BERG Reviewed-by: Jonas ABERG Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_bmdata.c | 19 ++--- drivers/power/ab8500_fg.c | 146 ++++++++++++++++++++++++++++++++--- drivers/power/abx500_chargalg.c | 30 +++---- include/linux/mfd/abx500.h | 6 +- include/linux/mfd/abx500/ab8500-bm.h | 2 + 5 files changed, 168 insertions(+), 35 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c index 0bf52369d6a5..20c157b4fe99 100644 --- a/drivers/power/ab8500_bmdata.c +++ b/drivers/power/ab8500_bmdata.c @@ -192,7 +192,7 @@ static struct abx500_battery_type bat_type_thermistor[] = { .nominal_voltage = 3700, .termination_vol = 4050, .termination_curr = 200, - .recharge_vol = 3990, + .recharge_cap = 95, .normal_cur_lvl = 400, .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, @@ -219,7 +219,7 @@ static struct abx500_battery_type bat_type_thermistor[] = { .nominal_voltage = 3600, .termination_vol = 4150, .termination_curr = 80, - .recharge_vol = 4130, + .recharge_cap = 95, .normal_cur_lvl = 700, .normal_vol_lvl = 4200, .maint_a_cur_lvl = 600, @@ -247,7 +247,7 @@ static struct abx500_battery_type bat_type_thermistor[] = { .nominal_voltage = 3600, .termination_vol = 4150, .termination_curr = 80, - .recharge_vol = 4130, + .recharge_cap = 95, .normal_cur_lvl = 700, .normal_vol_lvl = 4200, .maint_a_cur_lvl = 600, @@ -278,7 +278,7 @@ static struct abx500_battery_type bat_type_ext_thermistor[] = { .nominal_voltage = 3700, .termination_vol = 4050, .termination_curr = 200, - .recharge_vol = 3990, + .recharge_cap = 95, .normal_cur_lvl = 400, .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, @@ -310,7 +310,7 @@ static struct abx500_battery_type bat_type_ext_thermistor[] = { .nominal_voltage = 3700, .termination_vol = 4150, .termination_curr = 100, - .recharge_vol = 4130, + .recharge_cap = 95, .normal_cur_lvl = 700, .normal_vol_lvl = 4200, .maint_a_cur_lvl = 600, @@ -337,7 +337,7 @@ static struct abx500_battery_type bat_type_ext_thermistor[] = { .nominal_voltage = 3700, .termination_vol = 4150, .termination_curr = 100, - .recharge_vol = 4130, + .recharge_cap = 95, .normal_cur_lvl = 700, .normal_vol_lvl = 4200, .maint_a_cur_lvl = 600, @@ -364,7 +364,7 @@ static struct abx500_battery_type bat_type_ext_thermistor[] = { .nominal_voltage = 3700, .termination_vol = 4150, .termination_curr = 100, - .recharge_vol = 4130, + .recharge_cap = 95, .normal_cur_lvl = 700, .normal_vol_lvl = 4200, .maint_a_cur_lvl = 600, @@ -405,8 +405,8 @@ static const struct abx500_fg_parameters fg = { .lowbat_threshold = 3100, .battok_falling_th_sel0 = 2860, .battok_raising_th_sel1 = 2860, + .maint_thres = 95, .user_cap_limit = 15, - .maint_thres = 97, }; static const struct abx500_maxim_parameters maxi_params = { @@ -435,6 +435,7 @@ struct abx500_bm_data ab8500_bm_data = { .bkup_bat_v = BUP_VCH_SEL_2P6V, .bkup_bat_i = BUP_ICH_SEL_150UA, .no_maintenance = false, + .capacity_scaling = false, .adc_therm = ABx500_ADC_THERM_BATCTRL, .chg_unknown_bat = false, .enable_overshoot = false, @@ -479,7 +480,7 @@ int __devinit ab8500_bm_of_probe(struct device *dev, bm->chg_unknown_bat = true; bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; - bm->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130; + bm->bat_type[BATTERY_UNKNOWN].recharge_cap = 95; bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; } diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index f3dbba8b3925..76fab6b5c541 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -113,6 +113,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 +130,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 { @@ -1166,6 +1174,99 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di) return ret; } +/** + * 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 @@ -1214,16 +1315,24 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) } 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_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->bm->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 != + (di->bat_cap.permille) / 10) { dev_dbg(di->dev, "battery reported full " "but capacity dropping: %d\n", @@ -1272,6 +1381,14 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) } 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"); @@ -1337,7 +1454,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", @@ -2027,7 +2144,9 @@ static int ab8500_fg_get_property(struct power_supply *psy, val->intval = di->bat_cap.prev_mah; break; case POWER_SUPPLY_PROP_CAPACITY: - if (di->flags.batt_unknown && !di->bm->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 @@ -2091,6 +2210,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: @@ -2103,10 +2224,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; }; @@ -2146,8 +2270,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; diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 8b69da0ae5af..78b623572b52 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -33,9 +33,6 @@ /* End-of-charge criteria counter */ #define EOC_COND_CNT 10 -/* Recharge criteria counter */ -#define RCH_COND_CNT 3 - #define to_abx500_chargalg_device_info(x) container_of((x), \ struct abx500_chargalg, chargalg_psy); @@ -196,7 +193,6 @@ enum maxim_ret { * @dev: pointer to the structure device * @charge_status: battery operating status * @eoc_cnt: counter used to determine end-of_charge - * @rch_cnt: counter used to determine start of recharge * @maintenance_chg: indicate if maintenance charge is active * @t_hyst_norm temperature hysteresis when the temperature has been * over or under normal limits @@ -223,7 +219,6 @@ struct abx500_chargalg { struct device *dev; int charge_status; int eoc_cnt; - int rch_cnt; bool maintenance_chg; int t_hyst_norm; int t_hyst_lowhigh; @@ -858,6 +853,7 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) union power_supply_propval ret; int i, j; bool psy_found = false; + bool capacity_updated = false; psy = (struct power_supply *)data; ext = dev_get_drvdata(dev); @@ -870,6 +866,16 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) if (!psy_found) return 0; + /* + * If external is not registering 'POWER_SUPPLY_PROP_CAPACITY' to its + * property because of handling that sysfs entry on its own, this is + * the place to get the battery capacity. + */ + if (!ext->get_property(ext, POWER_SUPPLY_PROP_CAPACITY, &ret)) { + di->batt_data.percent = ret.intval; + capacity_updated = true; + } + /* Go through all properties for the psy */ for (j = 0; j < ext->num_properties; j++) { enum power_supply_property prop; @@ -1154,7 +1160,8 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) } break; case POWER_SUPPLY_PROP_CAPACITY: - di->batt_data.percent = ret.intval; + if (!capacity_updated) + di->batt_data.percent = ret.intval; break; default: break; @@ -1424,16 +1431,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_WAIT_FOR_RECHARGE_INIT: abx500_chargalg_hold_charging(di); abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE); - di->rch_cnt = RCH_COND_CNT; /* Intentional fallthrough */ case STATE_WAIT_FOR_RECHARGE: - if (di->batt_data.volt <= - di->bm->bat_type[di->bm->batt_id].recharge_vol) { - if (di->rch_cnt-- == 0) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); - } else - di->rch_cnt = RCH_COND_CNT; + if (di->batt_data.percent <= + di->bm->bat_type[di->bm->batt_id]. + recharge_cap) + abx500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_MAINTENANCE_A_INIT: diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 4906b1842d2f..0e6e90badfca 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -131,7 +131,7 @@ struct abx500_maxim_parameters { * @nominal_voltage: Nominal voltage of the battery in mV * @termination_vol: max voltage upto which battery can be charged * @termination_curr battery charging termination current in mA - * @recharge_vol battery voltage limit that will trigger a new + * @recharge_cap battery capacity limit that will trigger a new * full charging cycle in the case where maintenan- * -ce charging has been disabled * @normal_cur_lvl: charger current in normal state in mA @@ -160,7 +160,7 @@ struct abx500_battery_type { int nominal_voltage; int termination_vol; int termination_curr; - int recharge_vol; + int recharge_cap; int normal_cur_lvl; int normal_vol_lvl; int maint_a_cur_lvl; @@ -224,6 +224,7 @@ struct abx500_bm_charger_parameters { * @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 * @abx500_adc_therm placement of thermistor, batctrl or battemp adc * @chg_unknown_bat flag to enable charging of unknown batteries * @enable_overshoot flag to enable VBAT overshoot control @@ -254,6 +255,7 @@ struct abx500_bm_data { int bkup_bat_v; int bkup_bat_i; bool no_maintenance; + bool capacity_scaling; bool chg_unknown_bat; bool enable_overshoot; bool auto_trig; diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h index 6c6a02e53cd9..fac684a6f346 100644 --- a/include/linux/mfd/abx500/ab8500-bm.h +++ b/include/linux/mfd/abx500/ab8500-bm.h @@ -355,6 +355,7 @@ struct ab8500_bm_charger_parameters { * @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 * @adc_therm placement of thermistor, batctrl or battemp adc * @chg_unknown_bat flag to enable charging of unknown batteries * @enable_overshoot flag to enable VBAT overshoot control @@ -383,6 +384,7 @@ struct ab8500_bm_data { int bkup_bat_v; int bkup_bat_i; bool no_maintenance; + bool capacity_scaling; bool chg_unknown_bat; bool enable_overshoot; enum abx500_adc_therm adc_therm; -- cgit v1.2.3 From 129d583b4432375a9559708882172320e4c8fb94 Mon Sep 17 00:00:00 2001 From: Rickard Andersson Date: Fri, 11 Jan 2013 13:12:55 +0000 Subject: ab8500_fg: Balance IRQ enable In case of time out error IRQ needs to be disabled otherwise we will get unbalanced enable/disable pairs. Signed-off-by: Lee Jones Signed-off-by: Rickard Andersson Reviewed-by: Jonas ABERG Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_fg.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 76fab6b5c541..d2d14ea681a4 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -745,6 +745,7 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) dev_dbg(di->dev, "%s instant current: %d", __func__, res); return res; fail: + disable_irq(di->irq); mutex_unlock(&di->cc_lock); return ret; } -- cgit v1.2.3 From 6eaf8740dad8820ea708e83f14134401de1cff6e Mon Sep 17 00:00:00 2001 From: pender01 Date: Fri, 11 Jan 2013 13:12:59 +0000 Subject: ab8500_fg: Round capacity output Round the capacity values for better enduser experience. Signed-off-by: Lee Jones Signed-off-by: pender01 Reviewed-by: Jonas ABERG Tested-by: Marcus COOPER Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_fg.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index d2d14ea681a4..af0374620681 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -32,6 +32,7 @@ #include #include #include +#include #define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 @@ -1158,7 +1159,7 @@ 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->bm->cap_levels->critical || di->flags.low_bat) @@ -1279,6 +1280,7 @@ static void ab8500_fg_update_cap_scalers(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); @@ -1310,6 +1312,7 @@ 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; @@ -1319,7 +1322,7 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) * 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; changed = true; @@ -1332,19 +1335,18 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) di->bat_cap.prev_percent; di->bat_cap.cap_scale.disable_cap_level = 100; } - } else if ( di->bat_cap.prev_percent != - (di->bat_cap.permille) / 10) { + } 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 @@ -1354,11 +1356,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 @@ -1366,9 +1368,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; @@ -1376,7 +1378,7 @@ 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); } } -- cgit v1.2.3 From 8bcf3b39a8776630eeec51aa1180626d66dc51aa Mon Sep 17 00:00:00 2001 From: Hakan Berg Date: Fri, 11 Jan 2013 13:13:01 +0000 Subject: ab8500_fg: Added support for BATT_OVV Add support for the battery over-voltage situation Signed-off-by: Lee Jones Signed-off-by: Hakan Berg Reviewed-by: Karl KOMIEROWSKI Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_fg.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index af0374620681..2917def7621c 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -1840,24 +1840,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)); + } else { + dev_dbg(di->dev, "Battery recovered from OVV\n"); + di->flags.bat_ovv = false; + power_supply_changed(&di->fg_psy); } } @@ -2037,8 +2039,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); -- cgit v1.2.3 From f902dadc123376b973e5f9cb216a22675a2a9181 Mon Sep 17 00:00:00 2001 From: Paer-Olof Haakansson Date: Fri, 11 Jan 2013 13:13:05 +0000 Subject: ab8500_fg: Overflow in current calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When calculating the average current the nominator will overflow when the charging current is high. Signed-off-by: Lee Jones Signed-off-by: Henrik Sölver Reviewed-by: Par-Olof HAKANSSON Reviewed-by: Jonas ABERG Tested-by: Par-Olof HAKANSSON Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_fg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 2917def7621c..570577c32ade 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -805,12 +805,9 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) /* * 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->bm->fg_res * (di->fg_samples / 4)); @@ -821,6 +818,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, -- cgit v1.2.3 From 41ce25657bcd631235c123ace9d2f37c995e123d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 11 Jan 2013 13:13:06 +0000 Subject: ab8500_fg: Remove pointless round_jiffies() call As HZ is a full-second, there is little point in rounding it. Let's save a few cycles by using HZ directly. Signed-off-by: Lee Jones Signed-off-by: Anton Vorontsov --- drivers/power/ab8500_fg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 570577c32ade..cd03549b6227 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -1854,7 +1854,7 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work) } /* 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; -- cgit v1.2.3 From 75f2a219ff11e6707903194009656820bba2d5c6 Mon Sep 17 00:00:00 2001 From: Hakan Berg Date: Thu, 10 May 2012 08:43:25 +0200 Subject: ab8500-fg: Adjust for RF bursts voltage drops Changed conditions for restarting low battery measurements counter and adjusted the interval between measurements to avoid RF burst induced voltage drops, and to shorten time to decide to shut down. Signed-off-by: Hakan Berg Signed-off-by: Martin Bergstrom Signed-off-by: Lee Jones Reviewed-by: Jonas ABERG Reviewed-by: Marcus COOPER --- drivers/power/ab8500_fg.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index cd03549b6227..a0cbbd393fc9 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -43,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 */ @@ -169,6 +169,7 @@ 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 @@ -210,6 +211,7 @@ 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; @@ -1879,25 +1881,29 @@ static void ab8500_fg_low_bat_work(struct work_struct *work) /* Check if LOW_BAT still fulfilled */ if (vbat < di->bm->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)); + /* 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; } /** @@ -2056,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; @@ -2698,6 +2705,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) { -- cgit v1.2.3 From ffaa39d9edd7e3d620d14d574485e814edbf3950 Mon Sep 17 00:00:00 2001 From: Martin Bergström Date: Fri, 4 May 2012 14:43:50 +0200 Subject: ab8500-fg: Go to INIT_RECOVERY when charger removed When the charger is removed we need to go to INIT_RECOVERY state instead of directly to RECOVERY state. Signed-off-by: Martin Bergstrom Signed-off-by: Lee Jones Reviewed-by: Marcus COOPER Reviewed-by: Jonas ABERG Tested-by: Jonas ABERG --- drivers/power/ab8500_fg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index a0cbbd393fc9..c791a5cef2b1 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -1641,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); -- cgit v1.2.3 From 53ef1f590dc59f3c1478c68ea1f06a28f55ddccb Mon Sep 17 00:00:00 2001 From: Jonas Aaberg Date: Mon, 21 May 2012 16:05:01 +0200 Subject: ab8500-bm: Flush all work queues before suspending Flush all workqueues at suspend time to avoid suspending during work. Signed-off-by: Jonas Aaberg Signed-off-by: Lee Jones Reviewed-by: Marcus COOPER --- drivers/power/ab8500_charger.c | 11 +++++++++++ drivers/power/ab8500_fg.c | 5 +++++ 2 files changed, 16 insertions(+) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index da965ee615cc..a632b94e38b9 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2866,6 +2866,17 @@ static int ab8500_charger_suspend(struct platform_device *pdev, if (delayed_work_pending(&di->check_hw_failure_work)) cancel_delayed_work(&di->check_hw_failure_work); + flush_delayed_work(&di->attach_work); + flush_delayed_work(&di->usb_charger_attached_work); + flush_delayed_work(&di->ac_charger_attached_work); + flush_delayed_work(&di->check_usbchgnotok_work); + flush_delayed_work(&di->check_vbat_work); + flush_delayed_work(&di->kick_wd_work); + + flush_work(&di->usb_link_status_work); + flush_work(&di->ac_work); + flush_work(&di->detect_usb_type_work); + return 0; } #else diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index c791a5cef2b1..f94c9661e47e 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2570,6 +2570,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 -- cgit v1.2.3 From 1a793a10899487d40ac3071f52a6e231260d935d Mon Sep 17 00:00:00 2001 From: Rajkumar Kasirajan Date: Wed, 30 May 2012 14:54:28 +0530 Subject: ab8500-fg: Use correct battery charge full design If battery is not identified while fg probe, mah_max_design gets initialized with unknown battery's charge full design. Reinitialize mah_max_design if battery is identified after fg probe. Signed-off-by: Rajkumar Kasirajan Signed-off-by: Lee Jones Reviewed-by: Vijaya Kumar K-1 Reviewed-by: Marcus COOPER Reviewed-by: Olivier CLERGEAUD Reviewed-by: Arun MURTHY Reviewed-by: Rabin VINCENT Tested-by: Rupesh KUMAR Tested-by: Jonas ABERG --- drivers/power/ab8500_fg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/power/ab8500_fg.c') diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index f94c9661e47e..25dae4c4b0ef 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2250,7 +2250,8 @@ 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->bm->bat_type[di->bm->batt_id]); -- cgit v1.2.3