Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5759344 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: batterydata: Add the ibat vs temp vs ACC lookup table"

parents c2f17812 2399ea65
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -41,6 +41,13 @@ Profile data node required subnodes:
			resistance lookup. The units for this lookup table
			should be degrees celsius and percent to milliohms.

Profile data node optional subnodes:
- qcom,ibat-acc-luit: A 2-dimentional lookup table that encodes temperature
			and battery current to battery ACC (apparent charge
			capacity). The units for this lookup table should be
			temperature in degrees celsius, ibat in milli-amps
			and ACC in milli-ampere-hour.

Lookup table required properties:
- qcom,lut-col-legend : An array that encodes the legend of the lookup table's
			columns. The length of this array will determine the
@@ -164,5 +171,14 @@ qcom,palladium-batterydata {
			<12886 1026 637 422 3269>,
			<170899 127211 98968 88907 77102>;
	};

	qcom,ibat-acc-lut {
		qcom,lut-col-legend = <(-20) 0 25>;
		qcom,lut-row-legend = <0 250 500 1000>;
		qcom,lut-data = <1470 1470 1473>,
				<1406 1406 1430>,
				<1247 1247 1414>,
				<764 764 1338>;
	};
};
+30 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -131,6 +131,30 @@ static int of_batterydata_read_pc_temp_ocv_lut(struct device_node *data_node,
	return 0;
}

static int of_batterydata_read_ibat_temp_acc_lut(struct device_node *data_node,
			const char *name, struct ibat_temp_acc_lut *lut)
{
	struct device_node *node = of_find_node_by_name(data_node, name);
	int rc;

	if (!lut) {
		pr_debug("No lut provided, skipping\n");
		return 0;
	} else if (!node) {
		pr_debug("Couldn't find %s node.\n", name);
		return 0;
	}
	rc = of_batterydata_read_lut(node, ACC_TEMP_COLS, ACC_IBAT_ROWS,
			&lut->cols, &lut->rows, lut->temp, lut->ibat,
			*lut->acc);
	if (rc) {
		pr_err("Failed to read %s node.\n", name);
		return rc;
	}

	return 0;
}

static int of_batterydata_read_single_row_lut(struct device_node *data_node,
				const char *name, struct single_row_lut *lut)
{
@@ -222,6 +246,11 @@ static int of_batterydata_load_battery_data(struct device_node *node,
	if (rc)
		return rc;

	rc = of_batterydata_read_ibat_temp_acc_lut(node, "qcom,ibat-acc-lut",
						batt_data->ibat_acc_lut);
	if (rc)
		return rc;

	rc = of_property_read_string(node, "qcom,battery-type",
					&batt_data->battery_type);
	if (rc) {
+82 −0
Original line number Diff line number Diff line
@@ -410,3 +410,85 @@ int interpolate_slope(struct pc_temp_ocv_lut *pc_temp_ocv,

	return slope;
}


int interpolate_acc(struct ibat_temp_acc_lut *ibat_acc_lut,
					int batt_temp, int ibat)
{
	int i, accrow1, accrow2, rows, cols;
	int row1 = 0;
	int row2 = 0;
	int acc;

	rows = ibat_acc_lut->rows;
	cols = ibat_acc_lut->cols;

	if (ibat > ibat_acc_lut->ibat[rows - 1]) {
		pr_debug("ibatt(%d) > max range(%d)\n", ibat,
					ibat_acc_lut->ibat[rows - 1]);
		row1 = rows - 1;
		row2 = rows - 2;
	} else if (ibat < ibat_acc_lut->ibat[0]) {
		pr_debug("ibatt(%d) < max range(%d)\n", ibat,
					ibat_acc_lut->ibat[0]);
		row1 = 0;
		row2 = 0;
	} else {
		for (i = 0; i < rows; i++) {
			if (ibat == ibat_acc_lut->ibat[i]) {
				row1 = i;
				row2 = i;
				break;
			}
			if (ibat < ibat_acc_lut->ibat[i]) {
				row1 = i;
				row2 = i - 1;
				break;
			}
		}
	}

	if (batt_temp < ibat_acc_lut->temp[0] * DEGC_SCALE)
		batt_temp = ibat_acc_lut->temp[0] * DEGC_SCALE;
	if (batt_temp > ibat_acc_lut->temp[cols - 1] * DEGC_SCALE)
		batt_temp = ibat_acc_lut->temp[cols - 1] * DEGC_SCALE;

	for (i = 0; i < cols; i++)
		if (batt_temp <= ibat_acc_lut->temp[i] * DEGC_SCALE)
			break;

	if (batt_temp == (ibat_acc_lut->temp[i] * DEGC_SCALE)) {
		acc = linear_interpolate(
			ibat_acc_lut->acc[row1][i],
			ibat_acc_lut->ibat[row1],
			ibat_acc_lut->acc[row2][i],
			ibat_acc_lut->ibat[row2],
			ibat);
		return acc;
	}

	accrow1 = linear_interpolate(
		ibat_acc_lut->acc[row1][i - 1],
		ibat_acc_lut->temp[i - 1] * DEGC_SCALE,
		ibat_acc_lut->acc[row1][i],
		ibat_acc_lut->temp[i] * DEGC_SCALE,
		batt_temp);

	accrow2 = linear_interpolate(
		ibat_acc_lut->acc[row2][i - 1],
		ibat_acc_lut->temp[i - 1] * DEGC_SCALE,
		ibat_acc_lut->acc[row2][i],
		ibat_acc_lut->temp[i] * DEGC_SCALE,
		batt_temp);

	acc = linear_interpolate(accrow1,
			ibat_acc_lut->ibat[row1],
			accrow2,
			ibat_acc_lut->ibat[row2],
			ibat);

	if (acc < 0)
		acc = 0;

	return acc;
}
+19 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@
#define PC_TEMP_ROWS		31
#define PC_TEMP_COLS		8

#define ACC_IBAT_ROWS		4
#define ACC_TEMP_COLS		3

#define MAX_SINGLE_LUT_COLS	20

#define MAX_BATT_ID_NUM		4
@@ -72,6 +75,14 @@ struct pc_temp_ocv_lut {
	int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
};

struct ibat_temp_acc_lut {
	int rows;
	int cols;
	int temp[ACC_TEMP_COLS];
	int ibat[ACC_IBAT_ROWS];
	int acc[ACC_IBAT_ROWS][ACC_TEMP_COLS];
};

struct batt_ids {
	int kohm[MAX_BATT_ID_NUM];
	int num;
@@ -115,6 +126,7 @@ struct bms_battery_data {
	struct single_row_lut	*fcc_temp_lut;
	struct single_row_lut	*fcc_sf_lut;
	struct pc_temp_ocv_lut	*pc_temp_ocv_lut;
	struct ibat_temp_acc_lut *ibat_acc_lut;
	struct sf_lut		*pc_sf_lut;
	struct sf_lut		*rbatt_sf_lut;
	int			default_rbatt_mohm;
@@ -148,6 +160,8 @@ int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
				int batt_temp_degc, int pc);
int interpolate_slope(struct pc_temp_ocv_lut *pc_temp_ocv,
					int batt_temp, int pc);
int interpolate_acc(struct ibat_temp_acc_lut *ibat_acc_lut,
					int batt_temp, int ibat);
int linear_interpolate(int y0, int x0, int y1, int x1, int x);
int is_between(int left, int right, int value);
#else
@@ -189,6 +203,11 @@ static inline int is_between(int left, int right, int value)
{
	return -EINVAL;
}
static inline int interpolate_acc(struct ibat_temp_acc_lut *ibat_acc_lut,
						int batt_temp, int ibat)
{
	return -EINVAL;
}
#endif

#endif