@@ -728,6 +728,8 @@ config BATTERY_GAUGE_LTC2941
config AB8500_BM
bool "AB8500 Battery Management Driver"
depends on AB8500_CORE && AB8500_GPADC && (IIO = y) && OF
+ select THERMAL
+ select THERMAL_OF
help
Say Y to include support for AB8500 battery management.
@@ -260,18 +260,6 @@ enum bup_vch_sel {
#define BUS_PP_PRECHG_CURRENT_MASK 0x0E
#define BUS_POWER_PATH_PRECHG_ENA 0x01
-/**
- * struct ab8500_res_to_temp - defines one point in a temp to res curve. To
- * be used in battery packs that combines the identification resistor with a
- * NTC resistor.
- * @temp: battery pack temperature in Celsius
- * @resist: NTC resistor net total resistance
- */
-struct ab8500_res_to_temp {
- int temp;
- int resist;
-};
-
/* Forward declaration */
struct ab8500_fg;
@@ -351,8 +339,6 @@ struct ab8500_maxim_parameters {
* @maint_b_chg_timer_h: charge time in maintenance B state
* @low_high_cur_lvl: charger current in temp low/high state in mA
* @low_high_vol_lvl: charger voltage in temp low/high state in mV'
- * @n_r_t_tbl_elements: number of elements in r_to_t_tbl
- * @r_to_t_tbl: table containing resistance to temp points
*/
struct ab8500_battery_type {
int resis_high;
@@ -365,8 +351,6 @@ struct ab8500_battery_type {
int maint_b_chg_timer_h;
int low_high_cur_lvl;
int low_high_vol_lvl;
- int n_temp_tbl_elements;
- const struct ab8500_res_to_temp *r_to_t_tbl;
};
/**
@@ -449,23 +433,6 @@ struct ab8500_bm_data {
const struct ab8500_fg_parameters *fg_params;
};
-enum {
- NTC_EXTERNAL = 0,
- NTC_INTERNAL,
-};
-
-/**
- * struct res_to_temp - defines one point in a temp to res curve. To
- * be used in battery packs that combines the identification resistor with a
- * NTC resistor.
- * @temp: battery pack temperature in Celsius
- * @resist: NTC resistor net total resistance
- */
-struct res_to_temp {
- int temp;
- int resist;
-};
-
/* Forward declaration */
struct ab8500_fg;
@@ -43,28 +43,6 @@ static struct power_supply_battery_ocv_table ocv_cap_tbl[] = {
{ .ocv = 3094000, .capacity = 0},
};
-/*
- * Note that the res_to_temp table must be strictly sorted by falling
- * resistance values to work.
- */
-static const struct ab8500_res_to_temp temp_tbl[] = {
- {-5, 214834},
- { 0, 162943},
- { 5, 124820},
- {10, 96520},
- {15, 75306},
- {20, 59254},
- {25, 47000},
- {30, 37566},
- {35, 30245},
- {40, 24520},
- {45, 20010},
- {50, 16432},
- {55, 13576},
- {60, 11280},
- {65, 9425},
-};
-
/*
* Note that the batres_vs_temp table must be strictly sorted by falling
* temperature values to work. Factory resistance is 300 mOhm and the
@@ -92,8 +70,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = {
.maint_b_chg_timer_h = 200,
.low_high_cur_lvl = 300,
.low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
- .r_to_t_tbl = temp_tbl,
};
static const struct ab8500_bm_capacity_levels cap_levels = {
@@ -26,13 +26,12 @@
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
+#include <linux/thermal.h>
#include <linux/iio/consumer.h>
#include <linux/fixp-arith.h>
#include "ab8500-bm.h"
-#define VTVOUT_V 1800
-
#define BTEMP_THERMAL_LOW_LIMIT -10
#define BTEMP_THERMAL_MED_LIMIT 0
#define BTEMP_THERMAL_HIGH_LIMIT_52 52
@@ -82,7 +81,7 @@ struct ab8500_btemp_ranges {
* @bat_temp: Dispatched battery temperature in degree Celsius
* @prev_bat_temp Last measured battery temperature in degree Celsius
* @parent: Pointer to the struct ab8500
- * @adc_btemp_ball: ADC channel for the battery ball temperature
+ * @tz: Thermal zone for the battery
* @adc_bat_ctrl: ADC channel for the battery control
* @fg: Pointer to the struct fg
* @bm: Platform specific battery management information
@@ -100,7 +99,7 @@ struct ab8500_btemp {
int bat_temp;
int prev_bat_temp;
struct ab8500 *parent;
- struct iio_channel *btemp_ball;
+ struct thermal_zone_device *tz;
struct iio_channel *bat_ctrl;
struct ab8500_fg *fg;
struct ab8500_bm_data *bm;
@@ -228,76 +227,6 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
return res;
}
-/**
- * ab8500_btemp_res_to_temp() - resistance to temperature
- * @di: pointer to the ab8500_btemp structure
- * @tbl: pointer to the resiatance to temperature table
- * @tbl_size: size of the resistance to temperature table
- * @res: resistance to calculate the temperature from
- *
- * This function returns the battery temperature in degrees Celsius
- * based on the NTC resistance.
- */
-static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
- const struct ab8500_res_to_temp *tbl, int tbl_size, int res)
-{
- int i;
- /*
- * Calculate the formula for the straight line
- * Simple interpolation if we are within
- * the resistance table limits, extrapolate
- * if resistance is outside the limits.
- */
- if (res > tbl[0].resist)
- i = 0;
- else if (res <= tbl[tbl_size - 1].resist)
- i = tbl_size - 2;
- else {
- i = 0;
- while (!(res <= tbl[i].resist &&
- res > tbl[i + 1].resist))
- i++;
- }
-
- return fixp_linear_interpolate(tbl[i].resist, tbl[i].temp,
- tbl[i + 1].resist, tbl[i + 1].temp,
- res);
-}
-
-/**
- * ab8500_btemp_measure_temp() - measure battery temperature
- * @di: pointer to the ab8500_btemp structure
- *
- * Returns battery temperature (on success) else the previous temperature
- */
-static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
-{
- int temp, ret;
- static int prev;
- int rntc, vntc;
-
- ret = iio_read_channel_processed(di->btemp_ball, &vntc);
- if (ret < 0) {
- dev_err(di->dev,
- "%s ADC conversion failed,"
- " using previous value\n", __func__);
- return prev;
- }
- /*
- * The PCB NTC is sourced from VTVOUT via a 230kOhm
- * resistor.
- */
- rntc = 230000 * vntc / (VTVOUT_V - vntc);
-
- temp = ab8500_btemp_res_to_temp(di,
- di->bm->bat_type->r_to_t_tbl,
- di->bm->bat_type->n_temp_tbl_elements, rntc);
- prev = temp;
-
- dev_dbg(di->dev, "Battery temperature is %d\n", temp);
- return temp;
-}
-
/**
* ab8500_btemp_id() - Identify the connected battery
* @di: pointer to the ab8500_btemp structure
@@ -347,6 +276,9 @@ static void ab8500_btemp_periodic_work(struct work_struct *work)
int bat_temp;
struct ab8500_btemp *di = container_of(work,
struct ab8500_btemp, btemp_periodic_work.work);
+ /* Assume 25 degrees celsius as start temperature */
+ static int prev = 25;
+ int ret;
if (!di->initialized) {
/* Identify the battery */
@@ -354,7 +286,17 @@ static void ab8500_btemp_periodic_work(struct work_struct *work)
dev_warn(di->dev, "failed to identify the battery\n");
}
- bat_temp = ab8500_btemp_measure_temp(di);
+ /* Failover if a reading is erroneous, use last meausurement */
+ ret = thermal_zone_get_temp(di->tz, &bat_temp);
+ if (ret) {
+ dev_err(di->dev, "error reading temperature\n");
+ bat_temp = prev;
+ } else {
+ /* Convert from millicentigrades to centigrades */
+ bat_temp /= 1000;
+ prev = bat_temp;
+ }
+
/*
* Filter battery temperature.
* Allow direct updates on temperature only if two samples result in
@@ -783,12 +725,11 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
di->dev = dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
- /* Get ADC channels */
- di->btemp_ball = devm_iio_channel_get(dev, "btemp_ball");
- if (IS_ERR(di->btemp_ball)) {
- ret = dev_err_probe(dev, PTR_ERR(di->btemp_ball),
- "failed to get BTEMP BALL ADC channel\n");
- return ret;
+ /* Get thermal zone and ADC */
+ di->tz = thermal_zone_get_zone_by_name("battery-thermal");
+ if (IS_ERR(di->tz)) {
+ return dev_err_probe(dev, PTR_ERR(di->tz),
+ "failed to get battery thermal zone\n");
}
di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl");
if (IS_ERR(di->bat_ctrl)) {
Instead of providing our own homebrewn thermal measurement code for an NTC and passing tables, we put the NTC thermistor into the device tree, create a passive thermal zone, and poll this thermal zone for the temperature. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- drivers/power/supply/Kconfig | 2 + drivers/power/supply/ab8500-bm.h | 33 --------- drivers/power/supply/ab8500_bmdata.c | 24 ------- drivers/power/supply/ab8500_btemp.c | 103 ++++++--------------------- 4 files changed, 24 insertions(+), 138 deletions(-)