Merge changes Ida66a62a,I206d116b,I29c71a20 into msm-3.0
* changes: power: pm8921-bms: expose start and end charging parameters power: pm8921-bms: refactor BMS driver code power: pm8921-bms: force max_voltage at end of charge
This commit is contained in:
committed by
QuIC Gerrit Code Review
commit
585339b007
@@ -403,10 +403,11 @@ static int pm8921_therm_mitigation[] = {
|
||||
325,
|
||||
};
|
||||
|
||||
#define MAX_VOLTAGE_MV 4200
|
||||
static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
|
||||
.safety_time = 180,
|
||||
.update_time = 60000,
|
||||
.max_voltage = 4200,
|
||||
.max_voltage = MAX_VOLTAGE_MV,
|
||||
.min_voltage = 3200,
|
||||
.resume_voltage_delta = 100,
|
||||
.term_current = 100,
|
||||
@@ -431,6 +432,7 @@ static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
|
||||
.i_test = 2500,
|
||||
.v_failure = 3000,
|
||||
.calib_delay_ms = 600000,
|
||||
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
|
||||
};
|
||||
|
||||
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
|
||||
|
||||
@@ -52,6 +52,26 @@ enum pmic_bms_interrupts {
|
||||
PM_BMS_MAX_INTS,
|
||||
};
|
||||
|
||||
struct pm8921_soc_params {
|
||||
uint16_t ocv_for_rbatt_raw;
|
||||
uint16_t vsense_for_rbatt_raw;
|
||||
uint16_t vbatt_for_rbatt_raw;
|
||||
uint16_t last_good_ocv_raw;
|
||||
int cc;
|
||||
|
||||
int ocv_for_rbatt_uv;
|
||||
int vsense_for_rbatt_uv;
|
||||
int vbatt_for_rbatt_uv;
|
||||
int last_good_ocv_uv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pm8921_bms_chip -
|
||||
* @bms_output_lock: lock to prevent concurrent bms reads
|
||||
* @bms_100_lock: lock to prevent concurrent updates to values that force
|
||||
* 100% charge
|
||||
*
|
||||
*/
|
||||
struct pm8921_bms_chip {
|
||||
struct device *dev;
|
||||
struct dentry *dent;
|
||||
@@ -77,6 +97,7 @@ struct pm8921_bms_chip {
|
||||
unsigned int pmic_bms_irq[PM_BMS_MAX_INTS];
|
||||
DECLARE_BITMAP(enabled_irqs, PM_BMS_MAX_INTS);
|
||||
spinlock_t bms_output_lock;
|
||||
spinlock_t bms_100_lock;
|
||||
struct single_row_lut *adjusted_fcc_temp_lut;
|
||||
unsigned int charging_began;
|
||||
unsigned int start_percent;
|
||||
@@ -84,6 +105,7 @@ struct pm8921_bms_chip {
|
||||
|
||||
uint16_t ocv_reading_at_100;
|
||||
int cc_reading_at_100;
|
||||
int max_voltage_uv;
|
||||
};
|
||||
|
||||
static struct pm8921_bms_chip *the_chip;
|
||||
@@ -129,6 +151,31 @@ module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
|
||||
static int bms_fake_battery;
|
||||
module_param(bms_fake_battery, int, 0644);
|
||||
|
||||
/* bms_start_XXX and bms_end_XXX are read only */
|
||||
static int bms_start_percent;
|
||||
static int bms_start_ocv_uv;
|
||||
static int bms_start_cc_mah;
|
||||
static int bms_end_percent;
|
||||
static int bms_end_ocv_uv;
|
||||
static int bms_end_cc_mah;
|
||||
|
||||
static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct kernel_param_ops bms_ro_param_ops = {
|
||||
.set = bms_ro_ops_set,
|
||||
.get = param_get_int,
|
||||
};
|
||||
module_param_cb(bms_start_percent, &bms_ro_param_ops, &bms_start_percent, 0644);
|
||||
module_param_cb(bms_start_ocv_uv, &bms_ro_param_ops, &bms_start_ocv_uv, 0644);
|
||||
module_param_cb(bms_start_cc_mah, &bms_ro_param_ops, &bms_start_cc_mah, 0644);
|
||||
|
||||
module_param_cb(bms_end_percent, &bms_ro_param_ops, &bms_end_percent, 0644);
|
||||
module_param_cb(bms_end_ocv_uv, &bms_ro_param_ops, &bms_end_ocv_uv, 0644);
|
||||
module_param_cb(bms_end_cc_mah, &bms_ro_param_ops, &bms_end_cc_mah, 0644);
|
||||
|
||||
static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp);
|
||||
static void readjust_fcc_table(void)
|
||||
{
|
||||
@@ -314,9 +361,6 @@ static int pm_bms_read_output_data(struct pm8921_bms_chip *chip, int type,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Output register data must be held (locked) while reading output */
|
||||
WARN_ON(!(reg && HOLD_OREG_DATA));
|
||||
|
||||
rc = pm_bms_masked_write(chip, BMS_CONTROL, SELECT_OUTPUT_DATA,
|
||||
type << SELECT_OUTPUT_TYPE_SHIFT);
|
||||
if (rc) {
|
||||
@@ -425,96 +469,28 @@ static int read_cc(struct pm8921_bms_chip *chip, int *result)
|
||||
}
|
||||
*result = msw << 16 | lsw;
|
||||
pr_debug("msw = %04x lsw = %04x cc = %d\n", msw, lsw, *result);
|
||||
*result = *result - chip->cc_reading_at_100;
|
||||
pr_debug("cc = %d after subtracting %d\n",
|
||||
*result, chip->cc_reading_at_100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_last_good_ocv(struct pm8921_bms_chip *chip, uint *result)
|
||||
static int convert_vbatt_raw_to_uv(struct pm8921_bms_chip *chip,
|
||||
uint16_t reading, int *result)
|
||||
{
|
||||
int rc;
|
||||
uint16_t reading;
|
||||
|
||||
rc = pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &reading);
|
||||
if (rc) {
|
||||
pr_err("fail to read LAST_GOOD_OCV_VALUE rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (chip->ocv_reading_at_100 != reading) {
|
||||
chip->ocv_reading_at_100 = 0;
|
||||
chip->cc_reading_at_100 = 0;
|
||||
*result = xoadc_reading_to_microvolt(reading);
|
||||
pr_debug("raw = %04x ocv_uV = %u\n", reading, *result);
|
||||
*result = adjust_xo_vbatt_reading(chip, *result);
|
||||
pr_debug("after adj ocv_uV = %u\n", *result);
|
||||
if (*result != 0)
|
||||
last_ocv_uv = *result;
|
||||
} else {
|
||||
/*
|
||||
* force 100% ocv by selecting the highest profiled ocv
|
||||
* This is the first row last column entry in the ocv
|
||||
* lookup table
|
||||
*/
|
||||
int cols = chip->pc_temp_ocv_lut->cols;
|
||||
|
||||
pr_debug("Forcing max voltage %d\n",
|
||||
1000 * chip->pc_temp_ocv_lut->ocv[0][cols-1]);
|
||||
*result = 1000 * chip->pc_temp_ocv_lut->ocv[0][cols-1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_vbatt_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
|
||||
{
|
||||
int rc;
|
||||
uint16_t reading;
|
||||
|
||||
rc = pm_bms_read_output_data(chip, VBATT_FOR_RBATT, &reading);
|
||||
if (rc) {
|
||||
pr_err("fail to read VBATT_FOR_RBATT rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
*result = xoadc_reading_to_microvolt(reading);
|
||||
pr_debug("raw = %04x vbatt_for_r_microV = %u\n", reading, *result);
|
||||
pr_debug("raw = %04x vbatt = %u\n", reading, *result);
|
||||
*result = adjust_xo_vbatt_reading(chip, *result);
|
||||
pr_debug("after adj vbatt_for_r_uV = %u\n", *result);
|
||||
pr_debug("after adj vbatt = %u\n", *result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_vsense_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
|
||||
static int convert_vsense_to_uv(struct pm8921_bms_chip *chip,
|
||||
int16_t reading, int *result)
|
||||
{
|
||||
int rc;
|
||||
uint16_t reading;
|
||||
|
||||
rc = pm_bms_read_output_data(chip, VSENSE_FOR_RBATT, &reading);
|
||||
if (rc) {
|
||||
pr_err("fail to read VSENSE_FOR_RBATT rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
*result = pm8xxx_ccadc_reading_to_microvolt(chip->revision, reading);
|
||||
pr_debug("raw = %04x vsense_for_r_uV = %u\n", reading, *result);
|
||||
pr_debug("raw = %04x vsense = %d\n", reading, *result);
|
||||
*result = pm8xxx_cc_adjust_for_gain(*result);
|
||||
pr_debug("after adj vsense_for_r_uV = %u\n", *result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_ocv_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
|
||||
{
|
||||
int rc;
|
||||
uint16_t reading;
|
||||
|
||||
rc = pm_bms_read_output_data(chip, OCV_FOR_RBATT, &reading);
|
||||
if (rc) {
|
||||
pr_err("fail to read OCV_FOR_RBATT rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
*result = xoadc_reading_to_microvolt(reading);
|
||||
pr_debug("raw = %04x ocv_for_r_uV = %u\n", reading, *result);
|
||||
*result = adjust_xo_vbatt_reading(chip, *result);
|
||||
pr_debug("after adj ocv_for_r_uV = %u\n", *result);
|
||||
pr_debug("after adj vsense = %d\n", *result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -528,11 +504,8 @@ static int read_vsense_avg(struct pm8921_bms_chip *chip, int *result)
|
||||
pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
*result = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
|
||||
reading);
|
||||
pr_debug("raw = %04x vsense = %d\n", reading, *result);
|
||||
*result = pm8xxx_cc_adjust_for_gain((s64)*result);
|
||||
pr_debug("after adj vsense = %d\n", *result);
|
||||
|
||||
convert_vsense_to_uv(chip, reading, result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -790,37 +763,59 @@ static int interpolate_pc(struct pm8921_bms_chip *chip,
|
||||
return 100;
|
||||
}
|
||||
|
||||
static int calculate_rbatt(struct pm8921_bms_chip *chip)
|
||||
static int read_soc_params_raw(struct pm8921_bms_chip *chip,
|
||||
struct pm8921_soc_params *raw)
|
||||
{
|
||||
int rc;
|
||||
unsigned int ocv, vsense, vbatt, r_batt;
|
||||
unsigned long flags;
|
||||
|
||||
rc = read_ocv_for_rbatt(chip, &ocv);
|
||||
if (rc) {
|
||||
pr_err("fail to read ocv_for_rbatt rc = %d\n", rc);
|
||||
ocv = 0;
|
||||
}
|
||||
spin_lock_irqsave(&chip->bms_output_lock, flags);
|
||||
pm_bms_lock_output_data(chip);
|
||||
|
||||
rc = read_vbatt_for_rbatt(chip, &vbatt);
|
||||
if (rc) {
|
||||
pr_err("fail to read vbatt_for_rbatt rc = %d\n", rc);
|
||||
ocv = 0;
|
||||
}
|
||||
pm_bms_read_output_data(chip,
|
||||
OCV_FOR_RBATT, &raw->ocv_for_rbatt_raw);
|
||||
pm_bms_read_output_data(chip,
|
||||
VBATT_FOR_RBATT, &raw->vbatt_for_rbatt_raw);
|
||||
pm_bms_read_output_data(chip,
|
||||
VSENSE_FOR_RBATT, &raw->vsense_for_rbatt_raw);
|
||||
pm_bms_read_output_data(chip,
|
||||
LAST_GOOD_OCV_VALUE, &raw->last_good_ocv_raw);
|
||||
read_cc(chip, &raw->cc);
|
||||
|
||||
rc = read_vsense_for_rbatt(chip, &vsense);
|
||||
if (rc) {
|
||||
pr_err("fail to read vsense_for_rbatt rc = %d\n", rc);
|
||||
ocv = 0;
|
||||
}
|
||||
if (ocv == 0
|
||||
|| ocv == vbatt
|
||||
|| vsense == 0) {
|
||||
pm_bms_unlock_output_data(chip);
|
||||
spin_unlock_irqrestore(&chip->bms_output_lock, flags);
|
||||
|
||||
convert_vbatt_raw_to_uv(chip,
|
||||
raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
|
||||
convert_vbatt_raw_to_uv(chip,
|
||||
raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
|
||||
convert_vbatt_raw_to_uv(chip,
|
||||
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
|
||||
convert_vsense_to_uv(chip,
|
||||
raw->vsense_for_rbatt_raw, &raw->vsense_for_rbatt_uv);
|
||||
|
||||
if (raw->last_good_ocv_uv)
|
||||
last_ocv_uv = raw->last_good_ocv_uv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int calculate_rbatt(struct pm8921_bms_chip *chip,
|
||||
struct pm8921_soc_params *raw)
|
||||
{
|
||||
unsigned int r_batt;
|
||||
|
||||
if (raw->ocv_for_rbatt_uv == 0
|
||||
|| raw->ocv_for_rbatt_uv == raw->vbatt_for_rbatt_uv
|
||||
|| raw->vsense_for_rbatt_raw == 0) {
|
||||
pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
|
||||
"vsen = %d\n",
|
||||
ocv, vbatt, vsense);
|
||||
raw->ocv_for_rbatt_uv,
|
||||
raw->vbatt_for_rbatt_uv,
|
||||
raw->vsense_for_rbatt_raw);
|
||||
return -EINVAL;
|
||||
}
|
||||
r_batt = ((ocv - vbatt) * chip->r_sense) / vsense;
|
||||
r_batt = ((raw->ocv_for_rbatt_uv - raw->vbatt_for_rbatt_uv)
|
||||
* chip->r_sense) / raw->vsense_for_rbatt_uv;
|
||||
last_rbatt = r_batt;
|
||||
pr_debug("r_batt = %umilliOhms", r_batt);
|
||||
return r_batt;
|
||||
@@ -866,6 +861,7 @@ static int get_battery_uvolts(struct pm8921_bms_chip *chip, int *uvolts)
|
||||
static int adc_based_ocv(struct pm8921_bms_chip *chip, int *ocv)
|
||||
{
|
||||
int vbatt, rbatt, ibatt, rc;
|
||||
struct pm8921_soc_params raw;
|
||||
|
||||
rc = get_battery_uvolts(chip, &vbatt);
|
||||
if (rc) {
|
||||
@@ -879,7 +875,9 @@ static int adc_based_ocv(struct pm8921_bms_chip *chip, int *ocv)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rbatt = calculate_rbatt(the_chip);
|
||||
read_soc_params_raw(chip, &raw);
|
||||
|
||||
rbatt = calculate_rbatt(the_chip, &raw);
|
||||
if (rbatt < 0)
|
||||
rbatt = (last_rbatt < 0) ? DEFAULT_RBATT_MOHMS : last_rbatt;
|
||||
*ocv = vbatt + ibatt * rbatt;
|
||||
@@ -903,13 +901,13 @@ static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, int batt_temp,
|
||||
return pc;
|
||||
}
|
||||
|
||||
static void calculate_cc_mah(struct pm8921_bms_chip *chip, int64_t *val,
|
||||
static void calculate_cc_mah(struct pm8921_bms_chip *chip, int cc, int *val,
|
||||
int *coulumb_counter)
|
||||
{
|
||||
int rc;
|
||||
int64_t cc_voltage_uv, cc_uvh, cc_mah;
|
||||
|
||||
rc = read_cc(the_chip, coulumb_counter);
|
||||
*coulumb_counter = cc;
|
||||
*coulumb_counter -= chip->cc_reading_at_100;
|
||||
cc_voltage_uv = (int64_t)*coulumb_counter;
|
||||
cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
|
||||
cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
|
||||
@@ -921,11 +919,12 @@ static void calculate_cc_mah(struct pm8921_bms_chip *chip, int64_t *val,
|
||||
}
|
||||
|
||||
static int calculate_unusable_charge_mah(struct pm8921_bms_chip *chip,
|
||||
struct pm8921_soc_params *raw,
|
||||
int fcc, int batt_temp, int chargecycles)
|
||||
{
|
||||
int rbatt, voltage_unusable_uv, pc_unusable;
|
||||
|
||||
rbatt = calculate_rbatt(chip);
|
||||
rbatt = calculate_rbatt(chip, raw);
|
||||
if (rbatt < 0) {
|
||||
rbatt = (last_rbatt < 0) ? DEFAULT_RBATT_MOHMS : last_rbatt;
|
||||
pr_debug("rbatt unavailable assuming %d\n", rbatt);
|
||||
@@ -942,16 +941,26 @@ static int calculate_unusable_charge_mah(struct pm8921_bms_chip *chip,
|
||||
}
|
||||
|
||||
/* calculate remainging charge at the time of ocv */
|
||||
static int calculate_remaining_charge_mah(struct pm8921_bms_chip *chip, int fcc,
|
||||
int batt_temp, int chargecycles)
|
||||
static int calculate_remaining_charge_mah(struct pm8921_bms_chip *chip,
|
||||
struct pm8921_soc_params *raw,
|
||||
int fcc, int batt_temp,
|
||||
int chargecycles)
|
||||
{
|
||||
int rc, ocv, pc;
|
||||
int ocv, pc;
|
||||
|
||||
/* calculate remainging charge */
|
||||
ocv = 0;
|
||||
rc = read_last_good_ocv(chip, &ocv);
|
||||
if (rc)
|
||||
pr_debug("failed to read ocv rc = %d\n", rc);
|
||||
if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
|
||||
chip->ocv_reading_at_100 = 0;
|
||||
chip->cc_reading_at_100 = 0;
|
||||
ocv = raw->last_good_ocv_uv;
|
||||
} else {
|
||||
/*
|
||||
* force 100% ocv by selecting the highest voltage the
|
||||
* battery could every reach
|
||||
*/
|
||||
ocv = chip->max_voltage_uv;
|
||||
}
|
||||
|
||||
if (ocv == 0) {
|
||||
ocv = last_ocv_uv;
|
||||
@@ -964,11 +973,12 @@ static int calculate_remaining_charge_mah(struct pm8921_bms_chip *chip, int fcc,
|
||||
}
|
||||
|
||||
static void calculate_charging_params(struct pm8921_bms_chip *chip,
|
||||
struct pm8921_soc_params *raw,
|
||||
int batt_temp, int chargecycles,
|
||||
int *fcc,
|
||||
int *unusable_charge,
|
||||
int *remaining_charge,
|
||||
int64_t *cc_mah)
|
||||
int *cc_mah)
|
||||
{
|
||||
int coulumb_counter;
|
||||
unsigned long flags;
|
||||
@@ -977,38 +987,35 @@ static void calculate_charging_params(struct pm8921_bms_chip *chip,
|
||||
pr_debug("FCC = %umAh batt_temp = %d, cycles = %d",
|
||||
*fcc, batt_temp, chargecycles);
|
||||
|
||||
/* fcc doesnt need to be read from hardware, lock the bms now */
|
||||
spin_lock_irqsave(&chip->bms_output_lock, flags);
|
||||
pm_bms_lock_output_data(chip);
|
||||
|
||||
*unusable_charge = calculate_unusable_charge_mah(chip, *fcc,
|
||||
*unusable_charge = calculate_unusable_charge_mah(chip, raw, *fcc,
|
||||
batt_temp, chargecycles);
|
||||
|
||||
pr_debug("UUC = %umAh", *unusable_charge);
|
||||
|
||||
spin_lock_irqsave(&chip->bms_100_lock, flags);
|
||||
/* calculate remainging charge */
|
||||
*remaining_charge = calculate_remaining_charge_mah(chip, *fcc,
|
||||
*remaining_charge = calculate_remaining_charge_mah(chip, raw, *fcc,
|
||||
batt_temp, chargecycles);
|
||||
pr_debug("RC = %umAh\n", *remaining_charge);
|
||||
|
||||
/* calculate cc milli_volt_hour */
|
||||
calculate_cc_mah(chip, cc_mah, &coulumb_counter);
|
||||
pr_debug("cc_mah = %lldmAh cc = %d\n", *cc_mah, coulumb_counter);
|
||||
|
||||
pm_bms_unlock_output_data(chip);
|
||||
spin_unlock_irqrestore(&chip->bms_output_lock, flags);
|
||||
calculate_cc_mah(chip, raw->cc, cc_mah, &coulumb_counter);
|
||||
pr_debug("cc_mah = %dmAh raw->cc = %x cc = %x\n",
|
||||
*cc_mah, raw->cc, coulumb_counter);
|
||||
spin_unlock_irqrestore(&chip->bms_100_lock, flags);
|
||||
}
|
||||
|
||||
static int calculate_real_fcc(struct pm8921_bms_chip *chip,
|
||||
int batt_temp, int chargecycles,
|
||||
int *ret_fcc)
|
||||
struct pm8921_soc_params *raw,
|
||||
int batt_temp, int chargecycles,
|
||||
int *ret_fcc)
|
||||
{
|
||||
int fcc, unusable_charge;
|
||||
int remaining_charge;
|
||||
int64_t cc_mah;
|
||||
int cc_mah;
|
||||
int real_fcc;
|
||||
|
||||
calculate_charging_params(chip, batt_temp, chargecycles,
|
||||
calculate_charging_params(chip, raw, batt_temp, chargecycles,
|
||||
&fcc,
|
||||
&unusable_charge,
|
||||
&remaining_charge,
|
||||
@@ -1016,7 +1023,7 @@ static int calculate_real_fcc(struct pm8921_bms_chip *chip,
|
||||
|
||||
real_fcc = remaining_charge - cc_mah;
|
||||
*ret_fcc = fcc;
|
||||
pr_debug("real_fcc = %d, RC = %d CC = %lld fcc = %d\n",
|
||||
pr_debug("real_fcc = %d, RC = %d CC = %d fcc = %d\n",
|
||||
real_fcc, remaining_charge, cc_mah, fcc);
|
||||
return real_fcc;
|
||||
}
|
||||
@@ -1028,14 +1035,15 @@ static int calculate_real_fcc(struct pm8921_bms_chip *chip,
|
||||
*/
|
||||
#define BATTERY_POWER_SUPPLY_SOC 53
|
||||
static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
|
||||
int batt_temp, int chargecycles)
|
||||
struct pm8921_soc_params *raw,
|
||||
int batt_temp, int chargecycles)
|
||||
{
|
||||
int remaining_usable_charge, fcc, unusable_charge;
|
||||
int remaining_charge, soc;
|
||||
int update_userspace = 1;
|
||||
int64_t cc_mah;
|
||||
int cc_mah;
|
||||
|
||||
calculate_charging_params(chip, batt_temp, chargecycles,
|
||||
calculate_charging_params(chip, raw, batt_temp, chargecycles,
|
||||
&fcc,
|
||||
&unusable_charge,
|
||||
&remaining_charge,
|
||||
@@ -1057,7 +1065,7 @@ static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
|
||||
|
||||
if (soc < 0) {
|
||||
pr_err("bad rem_usb_chg = %d rem_chg %d,"
|
||||
"cc_mah %lld, unusb_chg %d\n",
|
||||
"cc_mah %d, unusb_chg %d\n",
|
||||
remaining_usable_charge, remaining_charge,
|
||||
cc_mah, unusable_charge);
|
||||
pr_err("for bad rem_usb_chg last_ocv_uv = %d"
|
||||
@@ -1209,6 +1217,7 @@ int pm8921_bms_get_percent_charge(void)
|
||||
{
|
||||
int batt_temp, rc;
|
||||
struct pm8xxx_adc_chan_result result;
|
||||
struct pm8921_soc_params raw;
|
||||
|
||||
if (!the_chip) {
|
||||
pr_err("called before initialization\n");
|
||||
@@ -1224,7 +1233,10 @@ int pm8921_bms_get_percent_charge(void)
|
||||
pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
|
||||
result.measurement);
|
||||
batt_temp = (int)result.physical;
|
||||
return calculate_state_of_charge(the_chip,
|
||||
|
||||
read_soc_params_raw(the_chip, &raw);
|
||||
|
||||
return calculate_state_of_charge(the_chip, &raw,
|
||||
batt_temp, last_chargecycles);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
|
||||
@@ -1254,7 +1266,28 @@ EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
|
||||
|
||||
void pm8921_bms_charging_began(void)
|
||||
{
|
||||
the_chip->start_percent = pm8921_bms_get_percent_charge();
|
||||
int batt_temp, coulumb_counter, rc;
|
||||
struct pm8xxx_adc_chan_result result;
|
||||
struct pm8921_soc_params raw;
|
||||
|
||||
rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
|
||||
if (rc) {
|
||||
pr_err("error reading adc channel = %d, rc = %d\n",
|
||||
the_chip->batt_temp_channel, rc);
|
||||
return;
|
||||
}
|
||||
pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
|
||||
result.measurement);
|
||||
batt_temp = (int)result.physical;
|
||||
|
||||
read_soc_params_raw(the_chip, &raw);
|
||||
|
||||
the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
|
||||
batt_temp, last_chargecycles);
|
||||
bms_start_percent = the_chip->start_percent;
|
||||
bms_start_ocv_uv = raw.last_good_ocv_uv;
|
||||
calculate_cc_mah(the_chip, raw.cc, &bms_start_cc_mah, &coulumb_counter);
|
||||
|
||||
pr_debug("start_percent = %u%%\n", the_chip->start_percent);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
|
||||
@@ -1262,22 +1295,27 @@ EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
|
||||
#define DELTA_FCC_PERCENT 3
|
||||
void pm8921_bms_charging_end(int is_battery_full)
|
||||
{
|
||||
int batt_temp, coulumb_counter, rc;
|
||||
struct pm8xxx_adc_chan_result result;
|
||||
struct pm8921_soc_params raw;
|
||||
|
||||
rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
|
||||
if (rc) {
|
||||
pr_err("error reading adc channel = %d, rc = %d\n",
|
||||
the_chip->batt_temp_channel, rc);
|
||||
return;
|
||||
}
|
||||
pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
|
||||
result.measurement);
|
||||
batt_temp = (int)result.physical;
|
||||
|
||||
read_soc_params_raw(the_chip, &raw);
|
||||
|
||||
if (is_battery_full && the_chip != NULL) {
|
||||
unsigned long flags;
|
||||
int batt_temp, rc, cc_reading;
|
||||
int fcc, new_fcc, delta_fcc;
|
||||
struct pm8xxx_adc_chan_result result;
|
||||
|
||||
rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
|
||||
if (rc) {
|
||||
pr_err("error reading adc channel = %d, rc = %d\n",
|
||||
the_chip->batt_temp_channel, rc);
|
||||
goto charge_cycle_calculation;
|
||||
}
|
||||
pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
|
||||
result.measurement);
|
||||
batt_temp = (int)result.physical;
|
||||
new_fcc = calculate_real_fcc(the_chip,
|
||||
new_fcc = calculate_real_fcc(the_chip, &raw,
|
||||
batt_temp, last_chargecycles,
|
||||
&fcc);
|
||||
delta_fcc = new_fcc - fcc;
|
||||
@@ -1296,21 +1334,22 @@ void pm8921_bms_charging_end(int is_battery_full)
|
||||
delta_fcc, DELTA_FCC_PERCENT, fcc);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&the_chip->bms_output_lock, flags);
|
||||
pm_bms_lock_output_data(the_chip);
|
||||
pm_bms_read_output_data(the_chip, LAST_GOOD_OCV_VALUE,
|
||||
&the_chip->ocv_reading_at_100);
|
||||
read_cc(the_chip, &cc_reading);
|
||||
pm_bms_unlock_output_data(the_chip);
|
||||
spin_unlock_irqrestore(&the_chip->bms_output_lock, flags);
|
||||
the_chip->cc_reading_at_100 = cc_reading;
|
||||
pr_debug("EOC ocv_reading = 0x%x cc_reading = %d\n",
|
||||
spin_lock_irqsave(&the_chip->bms_100_lock, flags);
|
||||
the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw;
|
||||
the_chip->cc_reading_at_100 = raw.cc;
|
||||
spin_unlock_irqrestore(&the_chip->bms_100_lock, flags);
|
||||
pr_debug("EOC ocv_reading = 0x%x cc = %d\n",
|
||||
the_chip->ocv_reading_at_100,
|
||||
the_chip->cc_reading_at_100);
|
||||
}
|
||||
|
||||
charge_cycle_calculation:
|
||||
the_chip->end_percent = pm8921_bms_get_percent_charge();
|
||||
the_chip->end_percent = calculate_state_of_charge(the_chip, &raw,
|
||||
batt_temp, last_chargecycles);
|
||||
|
||||
bms_end_percent = the_chip->end_percent;
|
||||
bms_end_ocv_uv = raw.last_good_ocv_uv;
|
||||
calculate_cc_mah(the_chip, raw.cc, &bms_end_cc_mah, &coulumb_counter);
|
||||
|
||||
if (the_chip->end_percent > the_chip->start_percent) {
|
||||
last_charge_increase =
|
||||
the_chip->end_percent - the_chip->start_percent;
|
||||
@@ -1472,24 +1511,26 @@ static int __devinit pm8921_bms_hw_init(struct pm8921_bms_chip *chip)
|
||||
|
||||
static void check_initial_ocv(struct pm8921_bms_chip *chip)
|
||||
{
|
||||
int ocv, rc;
|
||||
int ocv_uv, rc;
|
||||
int16_t ocv_raw;
|
||||
|
||||
/*
|
||||
* Check if a ocv is available in bms hw,
|
||||
* if not compute it here at boot time and save it
|
||||
* in the last_ocv_uv.
|
||||
*/
|
||||
ocv = 0;
|
||||
rc = read_last_good_ocv(chip, &ocv);
|
||||
if (rc || ocv == 0) {
|
||||
rc = adc_based_ocv(chip, &ocv);
|
||||
ocv_uv = 0;
|
||||
pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
|
||||
rc = convert_vbatt_raw_to_uv(chip, ocv_raw, &ocv_uv);
|
||||
if (rc || ocv_uv == 0) {
|
||||
rc = adc_based_ocv(chip, &ocv_uv);
|
||||
if (rc) {
|
||||
pr_err("failed to read adc based ocv rc = %d\n", rc);
|
||||
ocv = DEFAULT_OCV_MICROVOLTS;
|
||||
pr_err("failed to read adc based ocv_uv rc = %d\n", rc);
|
||||
ocv_uv = DEFAULT_OCV_MICROVOLTS;
|
||||
}
|
||||
last_ocv_uv = ocv;
|
||||
last_ocv_uv = ocv_uv;
|
||||
}
|
||||
pr_debug("ocv = %d last_ocv_uv = %d\n", ocv, last_ocv_uv);
|
||||
pr_debug("ocv_uv = %d last_ocv_uv = %d\n", ocv_uv, last_ocv_uv);
|
||||
}
|
||||
|
||||
static int64_t read_battery_id(struct pm8921_bms_chip *chip)
|
||||
@@ -1596,13 +1637,16 @@ static int get_calc(void *data, u64 * val)
|
||||
{
|
||||
int param = (int)data;
|
||||
int ret = 0;
|
||||
struct pm8921_soc_params raw;
|
||||
|
||||
read_soc_params_raw(the_chip, &raw);
|
||||
|
||||
*val = 0;
|
||||
|
||||
/* global irq number passed in via data */
|
||||
switch (param) {
|
||||
case CALC_RBATT:
|
||||
*val = calculate_rbatt(the_chip);
|
||||
*val = calculate_rbatt(the_chip, &raw);
|
||||
break;
|
||||
case CALC_FCC:
|
||||
*val = calculate_fcc(the_chip, test_batt_temp,
|
||||
@@ -1613,7 +1657,7 @@ static int get_calc(void *data, u64 * val)
|
||||
test_chargecycle);
|
||||
break;
|
||||
case CALC_SOC:
|
||||
*val = calculate_state_of_charge(the_chip,
|
||||
*val = calculate_state_of_charge(the_chip, &raw,
|
||||
test_batt_temp, test_chargecycle);
|
||||
break;
|
||||
case CALIB_HKADC:
|
||||
@@ -1637,6 +1681,9 @@ static int get_reading(void *data, u64 * val)
|
||||
{
|
||||
int param = (int)data;
|
||||
int ret = 0;
|
||||
struct pm8921_soc_params raw;
|
||||
|
||||
read_soc_params_raw(the_chip, &raw);
|
||||
|
||||
*val = 0;
|
||||
|
||||
@@ -1644,19 +1691,19 @@ static int get_reading(void *data, u64 * val)
|
||||
switch (param) {
|
||||
case CC_MSB:
|
||||
case CC_LSB:
|
||||
read_cc(the_chip, (int *)val);
|
||||
*val = raw.cc;
|
||||
break;
|
||||
case LAST_GOOD_OCV_VALUE:
|
||||
read_last_good_ocv(the_chip, (uint *)val);
|
||||
*val = raw.last_good_ocv_uv;
|
||||
break;
|
||||
case VBATT_FOR_RBATT:
|
||||
read_vbatt_for_rbatt(the_chip, (uint *)val);
|
||||
*val = raw.vbatt_for_rbatt_uv;
|
||||
break;
|
||||
case VSENSE_FOR_RBATT:
|
||||
read_vsense_for_rbatt(the_chip, (uint *)val);
|
||||
*val = raw.vsense_for_rbatt_uv;
|
||||
break;
|
||||
case OCV_FOR_RBATT:
|
||||
read_ocv_for_rbatt(the_chip, (uint *)val);
|
||||
*val = raw.ocv_for_rbatt_uv;
|
||||
break;
|
||||
case VSENSE_AVG:
|
||||
read_vsense_avg(the_chip, (uint *)val);
|
||||
@@ -1794,11 +1841,13 @@ static int __devinit pm8921_bms_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
spin_lock_init(&chip->bms_output_lock);
|
||||
spin_lock_init(&chip->bms_100_lock);
|
||||
chip->dev = &pdev->dev;
|
||||
chip->r_sense = pdata->r_sense;
|
||||
chip->i_test = pdata->i_test;
|
||||
chip->v_failure = pdata->v_failure;
|
||||
chip->calib_delay_ms = pdata->calib_delay_ms;
|
||||
chip->max_voltage_uv = pdata->max_voltage_uv;
|
||||
rc = set_battery_data(chip);
|
||||
if (rc) {
|
||||
pr_err("%s bad battery data %d\n", __func__, rc);
|
||||
|
||||
@@ -109,6 +109,7 @@ struct pm8921_bms_platform_data {
|
||||
unsigned int i_test;
|
||||
unsigned int v_failure;
|
||||
unsigned int calib_delay_ms;
|
||||
unsigned int max_voltage_uv;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
|
||||
|
||||
Reference in New Issue
Block a user