mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
temp_sensor: Separate ADC interface and thermistor maths
Separate the bd99992gw ADC interface from the NCP15WB thermistor adc-to-temp maths so that the thermistor can be used with various other interfaces. BUG=chrome-os-partner:44764 TEST=make buildall -j Manual on Glados. Boot to S0, run "temps". Verify that temperatures start around 28C and begin to increase after system is powered-on for a long duration. BRANCH=None Change-Id: I3e72e9f390feebaac2440dbe722485f8d1cf8c56 Signed-off-by: Wonjoon Lee <woojoo.lee@samsung.com> Reviewed-on: https://chromium-review.googlesource.com/296871 Reviewed-by: Shawn N <shawnn@chromium.org>
This commit is contained in:
@@ -71,6 +71,7 @@
|
||||
|
||||
#define CONFIG_TEMP_SENSOR
|
||||
#define CONFIG_TEMP_SENSOR_BD99992GW
|
||||
#define CONFIG_THERMISTOR_NCP15WB
|
||||
|
||||
/*
|
||||
* Allow dangerous commands.
|
||||
|
||||
@@ -58,6 +58,9 @@ driver-$(CONFIG_TEMP_SENSOR_G781)+=temp_sensor/g781.o
|
||||
driver-$(CONFIG_TEMP_SENSOR_TMP006)+=temp_sensor/tmp006.o
|
||||
driver-$(CONFIG_TEMP_SENSOR_TMP432)+=temp_sensor/tmp432.o
|
||||
|
||||
# Thermistors
|
||||
driver-$(CONFIG_THERMISTOR_NCP15WB)+=temp_sensor/thermistor_ncp15wb.o
|
||||
|
||||
# Type-C port controller (TCPC) drivers
|
||||
driver-$(CONFIG_USB_PD_TCPM_STUB)+=tcpm/stub.o
|
||||
driver-$(CONFIG_USB_PD_TCPM_TCPCI)+=tcpm/tcpci.o
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "hooks.h"
|
||||
#include "i2c.h"
|
||||
#include "temp_sensor.h"
|
||||
#include "thermistor.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -35,46 +36,6 @@ static enum bd99992gw_adc_channel
|
||||
*/
|
||||
#define ADC_LOOP_PERIOD BD99992GW_ADC1CNTL1_SLP27MS
|
||||
|
||||
/*
|
||||
* ADC-to-temp conversion assumes recommended thermistor / resistor
|
||||
* configuration specified in datasheet (NCP15WB* / 24.9K).
|
||||
* For 50C through 100C, use linear interpolation from discreet points
|
||||
* in table below. For temps < 50C, use a simplified linear function.
|
||||
*/
|
||||
#define ADC_DISCREET_RANGE_START_TEMP 50
|
||||
/* 10 bit ADC result corresponding to START_TEMP */
|
||||
#define ADC_DISCREET_RANGE_START_RESULT 407
|
||||
|
||||
#define ADC_DISCREET_RANGE_LIMIT_TEMP 100
|
||||
/* 10 bit ADC result corresponding to LIMIT_TEMP */
|
||||
#define ADC_DISCREET_RANGE_LIMIT_RESULT 107
|
||||
|
||||
/* Table entries in steppings of 5C */
|
||||
#define ADC_DISCREET_RANGE_STEP 5
|
||||
|
||||
/* Discreet range ADC results (9 bit) per temperature, in 5 degree steps */
|
||||
static const uint8_t adc_result[] = {
|
||||
203, /* 50 C */
|
||||
178, /* 55 C */
|
||||
157, /* 60 C */
|
||||
138, /* 65 C */
|
||||
121, /* 70 C */
|
||||
106, /* 75 C */
|
||||
93, /* 80 C */
|
||||
81, /* 85 C */
|
||||
70, /* 90 C */
|
||||
61, /* 95 C */
|
||||
53, /* 100 C */
|
||||
};
|
||||
|
||||
/*
|
||||
* From 20C (reasonable lower limit of temperatures we care about accuracy)
|
||||
* to 50C, the temperature curve is roughly linear, so we don't need to include
|
||||
* data points in our table.
|
||||
*/
|
||||
#define adc_to_temp(result) (ADC_DISCREET_RANGE_START_TEMP - \
|
||||
(((result) - ADC_DISCREET_RANGE_START_RESULT) * 3 + 16) / 32)
|
||||
|
||||
static int raw_read8(const int offset, int *data_ptr)
|
||||
{
|
||||
int ret;
|
||||
@@ -143,55 +104,14 @@ DECLARE_HOOK(HOOK_INIT, bd99992gw_init, HOOK_PRIO_DEFAULT);
|
||||
DECLARE_HOOK(HOOK_CHIPSET_RESUME, bd99992gw_init, HOOK_PRIO_DEFAULT);
|
||||
|
||||
/* Convert ADC result to temperature in celsius */
|
||||
test_export_static int bd99992gw_get_temp(uint16_t adc)
|
||||
static int bd99992gw_get_temp(uint16_t adc)
|
||||
{
|
||||
int temp;
|
||||
int head, tail, mid;
|
||||
uint8_t delta, step;
|
||||
|
||||
/* Is ADC result in linear range? */
|
||||
if (adc >= ADC_DISCREET_RANGE_START_RESULT) {
|
||||
temp = adc_to_temp(adc);
|
||||
}
|
||||
/* Hotter than our discreet range limit? */
|
||||
else if (adc <= ADC_DISCREET_RANGE_LIMIT_RESULT) {
|
||||
temp = ADC_DISCREET_RANGE_LIMIT_TEMP;
|
||||
}
|
||||
/* We're in the discreet range */
|
||||
else {
|
||||
/* Table uses 9 bit ADC values */
|
||||
adc /= 2;
|
||||
|
||||
/* Binary search to find proper table entry */
|
||||
head = 0;
|
||||
tail = ARRAY_SIZE(adc_result) - 1;
|
||||
while (head != tail) {
|
||||
mid = (head + tail) / 2;
|
||||
if (adc_result[mid] >= adc &&
|
||||
adc_result[mid+1] < adc)
|
||||
break;
|
||||
if (adc_result[mid] > adc)
|
||||
head = mid + 1;
|
||||
else
|
||||
tail = mid;
|
||||
}
|
||||
|
||||
/* Now fit between table entries using linear interpolation. */
|
||||
if (head != tail) {
|
||||
delta = adc_result[mid] - adc_result[mid + 1];
|
||||
step = ((adc_result[mid] - adc) *
|
||||
ADC_DISCREET_RANGE_STEP + delta / 2) / delta;
|
||||
} else {
|
||||
/* Edge case where adc = max */
|
||||
mid = head;
|
||||
step = 0;
|
||||
}
|
||||
|
||||
temp = ADC_DISCREET_RANGE_START_TEMP +
|
||||
ADC_DISCREET_RANGE_STEP * mid + step;
|
||||
}
|
||||
|
||||
return temp;
|
||||
#ifdef CONFIG_THERMISTOR_NCP15WB
|
||||
return ncp15wb_calculate_temp(adc);
|
||||
#else
|
||||
#error "Unknown thermistor for bd99992gw"
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get temperature from requested sensor */
|
||||
|
||||
20
driver/temp_sensor/thermistor.h
Normal file
20
driver/temp_sensor/thermistor.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* Thermistor module for Chrome EC */
|
||||
|
||||
#ifndef __CROS_EC_TEMP_SENSOR_THERMISTOR_H
|
||||
#define __CROS_EC_TEMP_SENSOR_THERMISTOR_H
|
||||
|
||||
/**
|
||||
* ncp15wb temperature conversion routine.
|
||||
*
|
||||
* @param adc 10bit raw data on adc.
|
||||
*
|
||||
* @return temperature in C.
|
||||
*/
|
||||
int ncp15wb_calculate_temp(uint16_t adc);
|
||||
|
||||
#endif /* __CROS_EC_TEMP_SENSOR_THERMISTOR_NCP15WB_H */
|
||||
100
driver/temp_sensor/thermistor_ncp15wb.c
Normal file
100
driver/temp_sensor/thermistor_ncp15wb.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* NCP15WB thermistor module for Chrome EC */
|
||||
|
||||
#include "common.h"
|
||||
#include "thermistor.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* ADC-to-temp conversion assumes recommended thermistor / resistor
|
||||
* configuration (NCP15WB* / 24.9K) with a 10-bit ADC.
|
||||
* For 50C through 100C, use linear interpolation from discreet points
|
||||
* in table below. For temps < 50C, use a simplified linear function.
|
||||
*/
|
||||
#define ADC_DISCREET_RANGE_START_TEMP 50
|
||||
/* 10 bit ADC result corresponding to START_TEMP */
|
||||
#define ADC_DISCREET_RANGE_START_RESULT 407
|
||||
|
||||
#define ADC_DISCREET_RANGE_LIMIT_TEMP 100
|
||||
/* 10 bit ADC result corresponding to LIMIT_TEMP */
|
||||
#define ADC_DISCREET_RANGE_LIMIT_RESULT 107
|
||||
|
||||
/* Table entries in steppings of 5C */
|
||||
#define ADC_DISCREET_RANGE_STEP 5
|
||||
|
||||
/* Discreet range ADC results (9 bit) per temperature, in 5 degree steps */
|
||||
static const uint8_t adc_result[] = {
|
||||
203, /* 50 C */
|
||||
178, /* 55 C */
|
||||
157, /* 60 C */
|
||||
138, /* 65 C */
|
||||
121, /* 70 C */
|
||||
106, /* 75 C */
|
||||
93, /* 80 C */
|
||||
81, /* 85 C */
|
||||
70, /* 90 C */
|
||||
61, /* 95 C */
|
||||
53, /* 100 C */
|
||||
};
|
||||
|
||||
/*
|
||||
* From 20C (reasonable lower limit of temperatures we care about accuracy)
|
||||
* to 50C, the temperature curve is roughly linear, so we don't need to include
|
||||
* data points in our table.
|
||||
*/
|
||||
#define adc_to_temp(result) (ADC_DISCREET_RANGE_START_TEMP - \
|
||||
(((result) - ADC_DISCREET_RANGE_START_RESULT) * 3 + 16) / 32)
|
||||
|
||||
/* Convert ADC result (10 bit) to temperature in celsius */
|
||||
int ncp15wb_calculate_temp(uint16_t adc)
|
||||
{
|
||||
int temp;
|
||||
int head, tail, mid;
|
||||
uint8_t delta, step;
|
||||
|
||||
/* Is ADC result in linear range? */
|
||||
if (adc >= ADC_DISCREET_RANGE_START_RESULT)
|
||||
temp = adc_to_temp(adc);
|
||||
/* Hotter than our discreet range limit? */
|
||||
else if (adc <= ADC_DISCREET_RANGE_LIMIT_RESULT)
|
||||
temp = ADC_DISCREET_RANGE_LIMIT_TEMP;
|
||||
/* We're in the discreet range */
|
||||
else {
|
||||
/* Table uses 9 bit ADC values */
|
||||
adc /= 2;
|
||||
|
||||
/* Binary search to find proper table entry */
|
||||
head = 0;
|
||||
tail = ARRAY_SIZE(adc_result) - 1;
|
||||
while (head != tail) {
|
||||
mid = (head + tail) / 2;
|
||||
if (adc_result[mid] >= adc &&
|
||||
adc_result[mid+1] < adc)
|
||||
break;
|
||||
if (adc_result[mid] > adc)
|
||||
head = mid + 1;
|
||||
else
|
||||
tail = mid;
|
||||
}
|
||||
|
||||
/* Now fit between table entries using linear interpolation. */
|
||||
if (head != tail) {
|
||||
delta = adc_result[mid] - adc_result[mid + 1];
|
||||
step = ((adc_result[mid] - adc) *
|
||||
ADC_DISCREET_RANGE_STEP + delta / 2) / delta;
|
||||
} else {
|
||||
/* Edge case where adc = max */
|
||||
mid = head;
|
||||
step = 0;
|
||||
}
|
||||
|
||||
temp = ADC_DISCREET_RANGE_START_TEMP +
|
||||
ADC_DISCREET_RANGE_STEP * mid + step;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
@@ -1497,6 +1497,8 @@
|
||||
#undef CONFIG_TEMP_SENSOR_TMP006 /* TI TMP006 sensor, on I2C bus */
|
||||
#undef CONFIG_TEMP_SENSOR_TMP432 /* TI TMP432 sensor, on I2C bus */
|
||||
|
||||
#undef CONFIG_THERMISTOR_NCP15WB /* NCP15WB thermistor */
|
||||
|
||||
/*
|
||||
* If defined, active-high GPIO which indicates temperature sensor chips are
|
||||
* powered. If not defined, temperature sensors are assumed to be always
|
||||
|
||||
@@ -78,9 +78,9 @@ int board_discharge_on_ac(int enabled);
|
||||
#define CONFIG_CHIPSET_CAN_THROTTLE
|
||||
#define CONFIG_FANS 1
|
||||
#define CONFIG_TEMP_SENSOR
|
||||
#define CONFIG_TEMP_SENSOR_BD99992GW
|
||||
#define CONFIG_THERMISTOR_NCP15WB
|
||||
#define I2C_PORT_THERMAL 1
|
||||
int bd99992gw_get_temp(uint16_t adc);
|
||||
int ncp15wb_calculate_temp(uint16_t adc);
|
||||
#endif
|
||||
|
||||
#ifdef TEST_FAN
|
||||
|
||||
@@ -480,11 +480,11 @@ static int test_several_limits(void)
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Tests for bd99992gw temperature sensor ADC-to-temp calculation */
|
||||
/* Tests for ncp15wb thermistor ADC-to-temp calculation */
|
||||
#define LOW_ADC_TEST_VALUE 887 /* 0 C */
|
||||
#define HIGH_ADC_TEST_VALUE 100 /* > 100C */
|
||||
|
||||
static int test_bd99992_adc_to_temp(void)
|
||||
static int test_ncp15wb_adc_to_temp(void)
|
||||
{
|
||||
int i;
|
||||
uint8_t temp;
|
||||
@@ -513,10 +513,10 @@ static int test_bd99992_adc_to_temp(void)
|
||||
* decrease.
|
||||
*/
|
||||
i = LOW_ADC_TEST_VALUE;
|
||||
temp = bd99992gw_get_temp(i);
|
||||
temp = ncp15wb_calculate_temp(i);
|
||||
|
||||
while (--i > HIGH_ADC_TEST_VALUE) {
|
||||
new_temp = bd99992gw_get_temp(i);
|
||||
new_temp = ncp15wb_calculate_temp(i);
|
||||
TEST_ASSERT(new_temp == temp ||
|
||||
new_temp == temp + 1);
|
||||
temp = new_temp;
|
||||
@@ -524,7 +524,7 @@ static int test_bd99992_adc_to_temp(void)
|
||||
|
||||
/* Verify several datapoints are within 1C accuracy */
|
||||
for (i = 0; i < ARRAY_SIZE(adc_temp_datapoints); ++i) {
|
||||
temp = bd99992gw_get_temp(adc_temp_datapoints[i].adc);
|
||||
temp = ncp15wb_calculate_temp(adc_temp_datapoints[i].adc);
|
||||
ASSERT(temp >= adc_temp_datapoints[i].temp - 1 &&
|
||||
temp <= adc_temp_datapoints[i].temp + 1);
|
||||
}
|
||||
@@ -544,6 +544,6 @@ void run_test(void)
|
||||
RUN_TEST(test_one_limit);
|
||||
RUN_TEST(test_several_limits);
|
||||
|
||||
RUN_TEST(test_bd99992_adc_to_temp);
|
||||
RUN_TEST(test_ncp15wb_adc_to_temp);
|
||||
test_print_result();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user