diff options
author | Vic Yang <victoryang@chromium.org> | 2012-02-15 15:38:06 -0800 |
---|---|---|
committer | Vic Yang <victoryang@chromium.org> | 2012-02-18 13:37:53 +0800 |
commit | 0fefd25c0c7d6517f47aac2da974495f72312014 (patch) | |
tree | d67e0071040aa53f3b3922f2ca39cce6ed4e4617 | |
parent | 737fbbd032ef937b37f2e5e833fa52455aa19c64 (diff) | |
download | chrome-ec-0fefd25c0c7d6517f47aac2da974495f72312014.tar.gz |
Temperature polling and temporal correction
A temperature polling task is added to achieve temporal correction and
also reduce the latency of reading temperature.
Factor out sensor specific part to keep code clean.
Signed-off-by: Vic Yang <victoryang@chromium.org>
BUG=chrome-os-partner:7801
TEST=On link, 'temps' shows all temperature readings.
Cover each sensor with hand and see object temperature rise.
Compilation succeeded on bds/adv/daisy/discovery.
Change-Id: I3c44c8b2e3ab2aa9ce640d3fc25e7fba56534b86
-rw-r--r-- | Makefile.toolchain | 2 | ||||
-rw-r--r-- | board/bds/board.h | 6 | ||||
-rw-r--r-- | board/bds/board_temp_sensor.c | 16 | ||||
-rw-r--r-- | board/bds/ec.tasklist | 1 | ||||
-rw-r--r-- | board/link/board.h | 18 | ||||
-rw-r--r-- | board/link/board_temp_sensor.c | 31 | ||||
-rw-r--r-- | board/link/ec.tasklist | 1 | ||||
-rw-r--r-- | chip/lm4/chip_temp_sensor.c | 13 | ||||
-rw-r--r-- | chip/lm4/peci.c | 16 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/main.c | 1 | ||||
-rw-r--r-- | common/temp_sensor.c | 236 | ||||
-rw-r--r-- | common/tmp006.c | 253 | ||||
-rw-r--r-- | include/chip_temp_sensor.h | 9 | ||||
-rw-r--r-- | include/peci.h | 5 | ||||
-rw-r--r-- | include/temp_sensor.h | 35 | ||||
-rw-r--r-- | include/tmp006.h | 30 |
17 files changed, 396 insertions, 278 deletions
diff --git a/Makefile.toolchain b/Makefile.toolchain index 6f75b65a45..adfc4b1fcf 100644 --- a/Makefile.toolchain +++ b/Makefile.toolchain @@ -25,7 +25,7 @@ CFLAGS_WARN=-Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ CFLAGS_DEBUG= -g CFLAGS_INCLUDE=$(foreach i,$(includes),-I$(i) ) CFLAGS_DEFINE=-DOUTDIR=$(out) -DCHIP=$(CHIP) -DTASKFILE=$(PROJECT).tasklist \ - -DBOARD=$(BOARD) -DBOARD_$(BOARD) -DCORE=$(CORE) + -DBOARD=$(BOARD) -DBOARD_$(BOARD) -DCORE=$(CORE) -DCHIP_$(CHIP) CPPFLAGS=$(CFLAGS_DEFINE) $(CFLAGS_INCLUDE) CFLAGS=$(CPPFLAGS) $(CFLAGS_CPU) $(CFLAGS_DEBUG) $(CFLAGS_WARN) BUILD_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN) diff --git a/board/bds/board.h b/board/bds/board.h index 7bd484edaf..dc96aa73c2 100644 --- a/board/bds/board.h +++ b/board/bds/board.h @@ -8,6 +8,9 @@ #ifndef __BOARD_H #define __BOARD_H +/* Config flags */ +#define CONFIG_TMP006 + /* 66.667 Mhz clock frequency */ #define CPU_CLOCK 66666667 @@ -125,10 +128,13 @@ enum gpio_signal { enum temp_sensor_id { TEMP_SENSOR_EC_INTERNAL = 0, /* EC internal temperature sensor */ TEMP_SENSOR_CASE_DIE, + TEMP_SENSOR_OBJECT, TEMP_SENSOR_COUNT }; +#define TMP006_COUNT 1 + void configure_board(void); #endif /* __BOARD_H */ diff --git a/board/bds/board_temp_sensor.c b/board/bds/board_temp_sensor.c index 2efa002cb9..5bc9a154f5 100644 --- a/board/bds/board_temp_sensor.c +++ b/board/bds/board_temp_sensor.c @@ -9,14 +9,22 @@ #include "chip_temp_sensor.h" #include "board.h" #include "i2c.h" +#include "tmp006.h" +#include "util.h" #define TEMP_CASE_DIE_REG_ADDR ((0x40 << 1) | I2C_FLAG_BIG_ENDIAN) #define TEMP_CASE_DIE_ADDR \ TMP006_ADDR(I2C_PORT_THERMAL, TEMP_CASE_DIE_REG_ADDR) +/* Temperature sensors data. Must be in the same order as enum + * temp_sensor_id. + */ const struct temp_sensor_t temp_sensors[TEMP_SENSOR_COUNT] = { - {"ECInternal", TEMP_SENSOR_NO_ADDR, - chip_temp_sensor_read, TEMP_SENSOR_NO_PRINT}, - {"CaseDie", TEMP_CASE_DIE_ADDR, - temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print} + {"ECInternal", chip_temp_sensor_get_val, 0}, + {"CaseDie", tmp006_get_val, 0}, + {"Object", tmp006_get_val, 0}, +}; + +const struct tmp006_t tmp006_sensors[TMP006_COUNT] = { + {"TMP006", TEMP_CASE_DIE_ADDR}, }; diff --git a/board/bds/ec.tasklist b/board/bds/ec.tasklist index a56e6769e1..a17d39199f 100644 --- a/board/bds/ec.tasklist +++ b/board/bds/ec.tasklist @@ -15,6 +15,7 @@ */ #define CONFIG_TASK_LIST \ TASK(WATCHDOG, watchdog_task, NULL) \ + TASK(TEMPSENSOR, temp_sensor_task, NULL) \ TASK(KEYSCAN, keyboard_scan_task, NULL) \ TASK(POWERBTN, power_button_task, NULL) \ TASK(X86POWER, x86_power_task, NULL) \ diff --git a/board/link/board.h b/board/link/board.h index eec67588c9..d061e90f63 100644 --- a/board/link/board.h +++ b/board/link/board.h @@ -10,6 +10,7 @@ /* Optional features */ #define CONFIG_PECI +#define CONFIG_TMP006 /* 66.667 Mhz clock frequency */ #define CPU_CLOCK 66666667 @@ -170,12 +171,20 @@ enum gpio_signal { enum temp_sensor_id { /* I2C die temperature sensor near CPU */ TEMP_SENSOR_I2C_DIE_NEAR_CPU = 0, - /* PCH temperature sensor */ + /* I2C object temperature sensor near CPU */ + TEMP_SENSOR_I2C_CPU, + /* I2C die temperature sensor near PCH */ TEMP_SENSOR_I2C_DIE_NEAR_PCH, - /* DDR memory temperature sensor */ + /* I2C object temperature sensor near PCH */ + TEMP_SENSOR_I2C_PCH, + /* I2C die temperature sensor near DDR memory */ TEMP_SENSOR_I2C_DIE_NEAR_DDR, - /* Battery charger temperature sensor */ + /* I2C object temperature sensor near CPU */ + TEMP_SENSOR_I2C_DDR, + /* I2C die temperature sensor near battery charger */ TEMP_SENSOR_I2C_DIE_NEAR_CHARGER, + /* I2C object temperature sensor near CPU */ + TEMP_SENSOR_I2C_CHARGER, /* EC internal temperature sensor */ TEMP_SENSOR_EC_INTERNAL, /* CPU die temperature via PECI */ @@ -186,6 +195,9 @@ enum temp_sensor_id { TEMP_SENSOR_COUNT }; +/* The number of TMP006 sensor chips on the board. */ +#define TMP006_COUNT 4 + void configure_board(void); #endif /* __BOARD_H */ diff --git a/board/link/board_temp_sensor.c b/board/link/board_temp_sensor.c index a8f3fae104..f8d3f93c2c 100644 --- a/board/link/board_temp_sensor.c +++ b/board/link/board_temp_sensor.c @@ -10,6 +10,8 @@ #include "board.h" #include "i2c.h" #include "peci.h" +#include "tmp006.h" +#include "util.h" #define TEMP_CPU_REG_ADDR ((0x40 << 1) | I2C_FLAG_BIG_ENDIAN) #define TEMP_PCH_REG_ADDR ((0x41 << 1) | I2C_FLAG_BIG_ENDIAN) @@ -25,16 +27,21 @@ * temp_sensor_id. */ const struct temp_sensor_t temp_sensors[TEMP_SENSOR_COUNT] = { - {"I2C_CPU", TEMP_CPU_ADDR, - temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print}, - {"I2C_PCH", TEMP_PCH_ADDR, - temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print}, - {"I2C_DDR", TEMP_DDR_ADDR, - temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print}, - {"I2C_Charger", TEMP_CHARGER_ADDR, - temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print}, - {"ECInternal", TEMP_SENSOR_NO_ADDR, - chip_temp_sensor_read, TEMP_SENSOR_NO_PRINT}, - {"PECI", TEMP_SENSOR_NO_ADDR, - peci_temp_sensor_read, TEMP_SENSOR_NO_PRINT}, + {"I2C_CPU-Die", tmp006_get_val, 0}, + {"I2C_CPU-Object", tmp006_get_val, 1}, + {"I2C_PCH-Die", tmp006_get_val, 2}, + {"I2C_PCH-Object", tmp006_get_val, 3}, + {"I2C_DDR-Die", tmp006_get_val, 4}, + {"I2C_DDR-Object", tmp006_get_val, 5}, + {"I2C_Charger-Die", tmp006_get_val, 6}, + {"I2C_Charger-Object", tmp006_get_val, 7}, + {"ECInternal", chip_temp_sensor_get_val, 0}, + {"PECI", peci_temp_sensor_get_val, 0}, +}; + +const struct tmp006_t tmp006_sensors[TMP006_COUNT] = { + {"CPU", TEMP_CPU_ADDR}, + {"PCH", TEMP_PCH_ADDR}, + {"DDR", TEMP_DDR_ADDR}, + {"Charger", TEMP_CHARGER_ADDR}, }; diff --git a/board/link/ec.tasklist b/board/link/ec.tasklist index a56e6769e1..a17d39199f 100644 --- a/board/link/ec.tasklist +++ b/board/link/ec.tasklist @@ -15,6 +15,7 @@ */ #define CONFIG_TASK_LIST \ TASK(WATCHDOG, watchdog_task, NULL) \ + TASK(TEMPSENSOR, temp_sensor_task, NULL) \ TASK(KEYSCAN, keyboard_scan_task, NULL) \ TASK(POWERBTN, power_button_task, NULL) \ TASK(X86POWER, x86_power_task, NULL) \ diff --git a/chip/lm4/chip_temp_sensor.c b/chip/lm4/chip_temp_sensor.c index b81d2b5383..89cac21765 100644 --- a/chip/lm4/chip_temp_sensor.c +++ b/chip/lm4/chip_temp_sensor.c @@ -9,9 +9,18 @@ #include "board.h" #include "temp_sensor.h" -int chip_temp_sensor_read(const struct temp_sensor_t* sensor) +static int last_val; + +int chip_temp_sensor_poll(void) +{ + last_val = adc_read_channel(ADC_CH_EC_TEMP); + + return EC_SUCCESS; +} + +int chip_temp_sensor_get_val(int idx) { - return adc_read_channel(ADC_CH_EC_TEMP); + return last_val; } int chip_temp_sensor_init(void) diff --git a/chip/lm4/peci.c b/chip/lm4/peci.c index eb82989be3..732a45b24d 100644 --- a/chip/lm4/peci.c +++ b/chip/lm4/peci.c @@ -28,6 +28,7 @@ #define PECI_TD_FET_NS 25 /* Guess; TODO: what is real delay */ #define PECI_TD_INT_NS 80 +static int last_temp_val; /* Configures the GPIOs for the PECI module. */ static void configure_gpios(void) @@ -50,10 +51,21 @@ int peci_get_cpu_temp(void) return v >> 6; } +int peci_temp_sensor_poll(void) +{ + int val = peci_get_cpu_temp(); + + if (val > 0) { + last_temp_val = val; + return EC_SUCCESS; + } + else + return EC_ERROR_UNKNOWN; +} -int peci_temp_sensor_read(const struct temp_sensor_t* sensor) +int peci_temp_sensor_get_val(int idx) { - return peci_get_cpu_temp(); + return last_temp_val; } /*****************************************************************************/ diff --git a/common/build.mk b/common/build.mk index a04fe3c11a..b6e32dfd73 100644 --- a/common/build.mk +++ b/common/build.mk @@ -16,6 +16,7 @@ common-$(CONFIG_TASK_GAIAPOWER)+=gaia_power.o common-$(CONFIG_FLASH)+=flash_commands.o common-$(CONFIG_PWM)+=pwm_commands.o common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o temp_sensor_commands.o +common-$(CONFIG_TMP006)+=tmp006.o common-$(CONFIG_LIGHTBAR)+=leds.o # Board driver modules diff --git a/common/main.c b/common/main.c index 7058aad009..f342bad9a0 100644 --- a/common/main.c +++ b/common/main.c @@ -30,6 +30,7 @@ #include "system.h" #include "task.h" #include "temp_sensor.h" +#include "tmp006.h" #include "timer.h" #include "uart.h" #include "usb_charge.h" diff --git a/common/temp_sensor.c b/common/temp_sensor.c index 9313623213..cc7dc25599 100644 --- a/common/temp_sensor.c +++ b/common/temp_sensor.c @@ -11,9 +11,10 @@ #include "util.h" #include "console.h" #include "board.h" +#include "peci.h" +#include "tmp006.h" #include "task.h" -#include "fpu.h" -#include "math.h" +#include "chip_temp_sensor.h" /* Defined in board_temp_sensor.c. Must be in the same order as * in enum temp_sensor_id. @@ -27,171 +28,31 @@ int temp_sensor_read(enum temp_sensor_id id) if (id < 0 || id >= TEMP_SENSOR_COUNT) return -1; sensor = temp_sensors + id; - return sensor->read(sensor); + return sensor->read(sensor->idx); } -int temp_sensor_tmp006_read_die_temp(const struct temp_sensor_t* sensor) +void poll_all_sensors(void) { - int traw, t; - int rv; - int addr = sensor->addr; - - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw); - if (rv) - return -1; - t = (int)(int16_t)traw / 128; - return t + 273; -} - -/* Calculate the remote object temperature. - * Parameters: - * Tdie: Die temperature in 1/100 K. - * Vobj: Voltage read from register 0. In nV. - * S0: Sensitivity factor in 1e-17. - * Return: - * Object temperature in 1/100 K. - */ -int temp_sensor_tmp006_calculate_object_temp(int Tdie_i, int Vobj_i, int S0_i) -{ -#ifdef CONFIG_FPU - float Tdie, Vobj, S0; - float Tx, S, Vos, Vx, fv, Tobj, T4; - int Tobj_i; - - enable_fpu(); - - Tdie = (float)Tdie_i * 1e-2f; - Vobj = (float)Vobj_i * 1e-9f; - S0 = (float)S0_i * 1e-17f; - - /* Calculate according to TMP006 users guide. */ - Tx = Tdie - 298.15f; - /* S is the sensitivity */ - S = S0 * (1.0f + 1.75e-3f * Tx - 1.678e-5f * Tx * Tx); - /* Vos is the offset voltage */ - Vos = -2.94e-5f - 5.7e-7f * Tx + 4.63e-9f * Tx * Tx; - Vx = Vobj - Vos; - /* fv is Seebeck coefficient f(Vobj) */ - fv = Vx + 13.4f * Vx * Vx; - - T4 = Tdie * Tdie * Tdie * Tdie + fv / S; - Tobj = sqrtf(sqrtf(T4)); - Tobj_i = (int32_t)(Tobj * 100.0f); - - disable_fpu(Tobj_i); - - return Tobj_i; -#else - /* This is the fixed-point version of object temperature calculation. - * Should be accurate but it is hard to prevent and debug - * overflow/underflow problem. Only use this version if there is no - * FPU support. - * Division is delayed when possible to preserve precision, but should - * not cause overflow. - * Assuming Tdie is between 200K and 400K, and S0 between 3e-14 and - * 9e-14, the maximum value during the calculation should be less than - * (1 << 30), which fits in int32_t. - */ - int32_t Tx, S19, Vos, Vx, fv9, ub, lb; - - Tx = Tdie - 29815; - /* S19 is the sensitivity multipled by 1e19 */ - S19 = S0 * (100000 + 175 * Tx / 100 - - 1678 * Tx / 100 * Tx / 100000) / 1000; - /* Vos is the offset voltage in nV */ - Vos = -29400 - 570 * Tx / 100 + 463 * Tx / 100 * Tx / 10000; - Vx = Vobj - Vos; - /* fv9 is Seebeck coefficient f(Vobj) multipled by 1e9 */ - fv9 = Vx + 134 * Vx / 100000 * Vx / 100000; - - /* The last step in the calculation involves square root, so we use - * binary search. - * Assuming the object temperature is between 200K and 400K, the search - * should take at most 14 iterations. - */ - ub = 40000; - lb = 20000; - while (lb != ub) { - int32_t t, rhs, lhs; - - t = (ub + lb) / 2; - lhs = t / 100 * t / 10000 * t / 10000 * (S19/100) / 1000 * t; - rhs = Tdie / 100 * Tdie / 10000 * Tdie / 10000 * (S19/100) / - 1000 * Tdie + fv9 * 1000; - if (lhs > rhs) - ub = t; - else - lb = t + 1; - } - - return ub; +#ifdef CONFIG_TMP006 + tmp006_poll(); +#endif +#ifdef CONFIG_PECI + peci_temp_sensor_poll(); +#endif +#ifdef CHIP_lm4 + chip_temp_sensor_poll(); #endif } -int temp_sensor_tmp006_read_object_temp(const struct temp_sensor_t* sensor) -{ - int traw, t; - int vraw, v; - int rv; - int addr = sensor->addr; - - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw); - if (rv) - return -1; - t = (int)(int16_t)traw / 128 + 273; - - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw); - if (rv) - return -1; - v = ((int)(int16_t)vraw * 15625) / 100; - - return temp_sensor_tmp006_calculate_object_temp(t * 100, v, 6400); -} - -void temp_sensor_tmp006_config(const struct temp_sensor_t* sensor) +void temp_sensor_task(void) { - int addr = sensor->addr; - - /* Configure the sensor: - * 0x7000 = bits 14:12 = continuous conversion - * 0x0400 = bits 11:9 = ADC conversion rate (1/sec) - * 0x0100 = bit 8 = DRDY pin enabled */ - - /* TODO: support shutdown mode for power-saving? */ - i2c_write16(TMP006_PORT(addr), TMP006_REG(addr), 0x02, 0x7500); + while (1) { + poll_all_sensors(); + /* Wait 1s */ + task_wait_msg(1000000); + } } -int temp_sensor_tmp006_print(const struct temp_sensor_t* sensor) -{ - int vraw, v; - int traw, t; - int rv; - int d; - int addr = sensor->addr; - - uart_printf("Debug data from %s:\n", sensor->name); - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xfe, &d); - if (rv) - return rv; - uart_printf(" Manufacturer ID: 0x%04x\n", d); - - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xff, &d); - uart_printf(" Device ID: 0x%04x\n", d); - - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x02, &d); - uart_printf(" Config: 0x%04x\n", d); - - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw); - v = ((int)(int16_t)vraw * 15625) / 100; - uart_printf(" Voltage: 0x%04x = %d nV\n", vraw, v); - - rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw); - t = ((int)(int16_t)traw * 100) / 128; - uart_printf(" Temperature: 0x%04x = %d.%02d C\n", - traw, t / 100, t > 0 ? t % 100 : 100 - (t % 100)); - - return EC_SUCCESS; -} /*****************************************************************************/ /* Console commands */ @@ -221,65 +82,6 @@ static int command_temps(int argc, char **argv) } DECLARE_CONSOLE_COMMAND(temps, command_temps); -static int command_sensor_info(int argc, char **argv) -{ - int i; - int rv, rv1; - const struct temp_sensor_t* sensor; - - rv1 = EC_SUCCESS; - for (i = 0; i < TEMP_SENSOR_COUNT; ++i) { - sensor = temp_sensors + i; - if (sensor->print == TEMP_SENSOR_NO_PRINT) - continue; - rv = sensor->print(sensor); - if (rv != EC_SUCCESS) - rv1 = rv; - } - - return rv1; -} -DECLARE_CONSOLE_COMMAND(tempsinfo, command_sensor_info); - -/* TMP006 object temperature calculation command. - * TODO: This command is only for debugging. Remove it when temporal correciton - * is done. - */ -static int command_sensor_remote(int argc, char **argv) -{ - char *e; - int32_t Td2, Vobj9, Sm03; - - if (argc != 4) { - uart_puts("Usage: tempcorrect <Tdie*100> <Vobj*10^9> <S0*10^11>\n"); - return EC_ERROR_UNKNOWN; - } - - Td2 = strtoi(argv[1], &e, 0); - if (e && *e) { - uart_puts("Bad Tdie.\n"); - return EC_ERROR_UNKNOWN; - } - - Vobj9 = strtoi(argv[2], &e, 0); - if (e && *e) { - uart_puts("Bad Vobj.\n"); - return EC_ERROR_UNKNOWN; - } - - Sm03 = strtoi(argv[3], &e, 0); - if (e && *e) { - uart_puts("Bad S0.\n"); - return EC_ERROR_UNKNOWN; - } - - uart_printf("%d\n", - temp_sensor_tmp006_calculate_object_temp(Td2, Vobj9, Sm03)); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(tempremote, command_sensor_remote); - /*****************************************************************************/ /* Initialization */ diff --git a/common/tmp006.c b/common/tmp006.c new file mode 100644 index 0000000000..70ad0eb688 --- /dev/null +++ b/common/tmp006.c @@ -0,0 +1,253 @@ +/* Copyright (c) 2012 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. + */ + +/* TMP006 temperature sensor module for Chrome EC */ + +#include "tmp006.h" +#include "temp_sensor.h" +#include "board.h" +#include "uart.h" +#include "util.h" +#include "console.h" +#include "task.h" +#include "fpu.h" +#include "math.h" +#include "i2c.h" + +/* Defined in board_temp_sensor.c. */ +extern const struct tmp006_t tmp006_sensors[TMP006_COUNT]; + +struct tmp006_data_t { + /* Object voltage */ + int v; + /* The last four die temperature value. Used as a circular buffer. */ + int t[4]; + /* The index of the current value in the dir temperature array. */ + int tidx; +}; + +static struct tmp006_data_t tmp006_data[TMP006_COUNT]; + +static int tmp006_read_die_temp(int idx) +{ + int pidx = (tmp006_data[idx].tidx - 1) & 0x3; + return tmp006_data[idx].t[pidx] / 100; +} + +/* Calculate the remote object temperature. + * Parameters: + * Tdie: Die temperature in 1/100 K. + * Vobj: Voltage read from register 0. In nV. + * S0: Sensitivity factor in 1e-17. + * Return: + * Object temperature in 1/100 K. + */ +static int tmp006_calculate_object_temp(int Tdie_i, int Vobj_i, int S0_i) +{ + float Tdie, Vobj, S0; + float Tx, S, Vos, Vx, fv, Tobj, T4; + int Tobj_i; + + enable_fpu(); + + Tdie = (float)Tdie_i * 1e-2f; + Vobj = (float)Vobj_i * 1e-9f; + S0 = (float)S0_i * 1e-17f; + + /* Calculate according to TMP006 users guide. */ + Tx = Tdie - 298.15f; + /* S is the sensitivity */ + S = S0 * (1.0f + 1.75e-3f * Tx - 1.678e-5f * Tx * Tx); + /* Vos is the offset voltage */ + Vos = -2.94e-5f - 5.7e-7f * Tx + 4.63e-9f * Tx * Tx; + Vx = Vobj - Vos; + /* fv is Seebeck coefficient f(Vobj) */ + fv = Vx + 13.4f * Vx * Vx; + + T4 = Tdie * Tdie * Tdie * Tdie + fv / S; + Tobj = sqrtf(sqrtf(T4)); + Tobj_i = (int32_t)(Tobj * 100.0f); + + disable_fpu(Tobj_i); + + return Tobj_i; +} + +/* Temporal Correction + * Parameters: + * T1-T4: Four die temperature readings separated by 1s in 1/100K. + * v: Voltage read from register 0. In nV. + * Return: + * Corrected object voltage in 1/100K. + */ +static int tmp006_correct_object_voltage(int T1, + int T2, + int T3, + int T4, + int Vobj) +{ + int Tslope = 3 * T1 + T2 - T3 - 3 * T4; + return Vobj + 296 * Tslope; +} + +static int tmp006_read_object_temp(int idx) +{ + int pidx = (tmp006_data[idx].tidx - 1) & 0x3; + int t = tmp006_data[idx].t[pidx]; + int v = tmp006_data[idx].v; + + v = tmp006_correct_object_voltage( + t, + tmp006_data[idx].t[(pidx + 3) & 3], + tmp006_data[idx].t[(pidx + 2) & 3], + tmp006_data[idx].t[(pidx + 1) & 3], + v); + + /* TODO: Calibrate the sensitivity factor. */ + return tmp006_calculate_object_temp(t, v, 6400) / 100; +} + +static int tmp006_poll_sensor(int sensor_id) +{ + int traw, t; + int vraw, v; + int rv; + int addr = tmp006_sensors[sensor_id].addr; + int idx; + + rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw); + if (rv) + return EC_ERROR_UNKNOWN; + t = ((int)(int16_t)traw * 100) / 128 + 27300; + + rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw); + if (rv) + return EC_ERROR_UNKNOWN; + v = ((int)(int16_t)vraw * 15625) / 100; + + idx = tmp006_data[sensor_id].tidx; + tmp006_data[sensor_id].t[idx] = t; + tmp006_data[sensor_id].v = v; + tmp006_data[sensor_id].tidx = (idx + 1) & 3; + + return EC_SUCCESS; +} + +static int tmp006_print(int idx) +{ + int vraw, v; + int traw, t; + int rv; + int d; + int addr = tmp006_sensors[idx].addr; + + uart_printf("Debug data from %s:\n", tmp006_sensors[idx].name); + rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xfe, &d); + if (rv) + return rv; + uart_printf(" Manufacturer ID: 0x%04x\n", d); + + rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0xff, &d); + uart_printf(" Device ID: 0x%04x\n", d); + + rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x02, &d); + uart_printf(" Config: 0x%04x\n", d); + + rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x00, &vraw); + v = ((int)(int16_t)vraw * 15625) / 100; + uart_printf(" Voltage: 0x%04x = %d nV\n", vraw, v); + + rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x01, &traw); + t = ((int)(int16_t)traw * 100) / 128; + uart_printf(" Temperature: 0x%04x = %d.%02d C\n", + traw, t / 100, t > 0 ? t % 100 : 100 - (t % 100)); + + return EC_SUCCESS; +} + + +int tmp006_get_val(int idx) +{ + /* Check the low bit to determine which temperature to read. */ + if ((idx & 0x1) == 0) + return tmp006_read_die_temp(idx >> 1); + else + return tmp006_read_object_temp(idx >> 1); +} + + +int tmp006_poll(void) +{ + int i; + int rv; + int rv1 = EC_SUCCESS; + + for (i = 0; i < TMP006_COUNT; ++i) { + rv = tmp006_poll_sensor(i); + if (rv != EC_SUCCESS) + rv1 = rv; + } + + return rv1; +} + + +/*****************************************************************************/ +/* Console commands */ + +/* TMP006 object temperature calculation command. + * TODO: This command is only for debugging. Remove it when temporal correciton + * is done. + */ +static int command_sensor_remote(int argc, char **argv) +{ + char *e; + int32_t Td2, Vobj9, Sm03; + + if (argc != 4) { + uart_puts("Usage: tempcorrect <Tdie*100> <Vobj*10^9> <S0*10^11>\n"); + return EC_ERROR_UNKNOWN; + } + + Td2 = strtoi(argv[1], &e, 0); + if (e && *e) { + uart_puts("Bad Tdie.\n"); + return EC_ERROR_UNKNOWN; + } + + Vobj9 = strtoi(argv[2], &e, 0); + if (e && *e) { + uart_puts("Bad Vobj.\n"); + return EC_ERROR_UNKNOWN; + } + + Sm03 = strtoi(argv[3], &e, 0); + if (e && *e) { + uart_puts("Bad S0.\n"); + return EC_ERROR_UNKNOWN; + } + + uart_printf("%d\n", + tmp006_calculate_object_temp(Td2, Vobj9, Sm03)); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(tempremote, command_sensor_remote); + +static int command_sensor_info(int argc, char **argv) +{ + int i; + int rv, rv1; + + rv1 = EC_SUCCESS; + for (i = 0; i < TMP006_COUNT; ++i) { + rv = tmp006_print(i); + if (rv != EC_SUCCESS) + rv1 = rv; + } + + return rv1; +} +DECLARE_CONSOLE_COMMAND(tmp006, command_sensor_info); diff --git a/include/chip_temp_sensor.h b/include/chip_temp_sensor.h index 22c358771b..08417cd3d8 100644 --- a/include/chip_temp_sensor.h +++ b/include/chip_temp_sensor.h @@ -10,10 +10,11 @@ struct temp_sensor_t; -/* Temperature reading function. Input pointer to a sensor in temp_sensors. - * Return temperature in K. - */ -int chip_temp_sensor_read(const struct temp_sensor_t* sensor); +/* Temperature polling function. */ +int chip_temp_sensor_poll(void); + +/* Temperature reading function. Return temperature in K. */ +int chip_temp_sensor_get_val(int idx); int chip_temp_sensor_init(void); diff --git a/include/peci.h b/include/peci.h index 11aead9bb1..2b2c33f4a7 100644 --- a/include/peci.h +++ b/include/peci.h @@ -24,6 +24,9 @@ int peci_get_cpu_temp(void); /* Reads the CPU temperature sensor via PECI. This interface is for the * temperature sensor module. Returns the temperature in degrees K, or -1 if * error. */ -int peci_temp_sensor_read(const struct temp_sensor_t *sensor); +int peci_temp_sensor_get_val(int idx); + +/* Temperature polling of CPU temperature sensor via PECI. */ +int peci_temp_sensor_poll(void); #endif /* __CROS_EC_PECI_H */ diff --git a/include/temp_sensor.h b/include/temp_sensor.h index fb35260e12..b20c77fe88 100644 --- a/include/temp_sensor.h +++ b/include/temp_sensor.h @@ -16,24 +16,12 @@ enum temp_sensor_id; struct temp_sensor_t { const char* name; - /* Sensor address. Used by read and print functions. */ - int addr; /* Read sensor value and return temperature in K. */ - int (*read)(const struct temp_sensor_t* self); - /* Print debug info on console. */ - int (*print)(const struct temp_sensor_t* self); + int (*read)(int idx); + /* Index among the same kind of sensors. */ + int idx; }; -/* Dummy value to put in "addr" field in temp_sensor_t if we don't need to - * specify address. - */ -#define TEMP_SENSOR_NO_ADDR 0 - -/* Dummy value to put in "print" field in temp_sensor_t if we don't have debug - * function for a sensor. - */ -#define TEMP_SENSOR_NO_PRINT 0 - /* Initializes the module. */ int temp_sensor_init(void); @@ -41,21 +29,4 @@ int temp_sensor_init(void); * or -1 if error. */ int temp_sensor_read(enum temp_sensor_id id); - -#define TMP006_ADDR(PORT,REG) ((PORT << 16) + REG) -#define TMP006_PORT(ADDR) (ADDR >> 16) -#define TMP006_REG(ADDR) (ADDR & 0xffff) - -/* Read TI TMP006 die temperature sensor. Return temperature in K. */ -int temp_sensor_tmp006_read_die_temp(const struct temp_sensor_t* sensor); - -/* Read TI TMP006 object temperature sensor. Return temperature in K. */ -int temp_sensor_tmp006_read_object_temp(const struct temp_sensor_t* sensor); - -/* Configure TMP006 DRDY pin. */ -void temp_sensor_tmp006_config(const struct temp_sensor_t* sensor); - -/* Print debug messages for TMP006. */ -int temp_sensor_tmp006_print(const struct temp_sensor_t* sensor); - #endif /* __CROS_EC_TEMP_SENSOR_H */ diff --git a/include/tmp006.h b/include/tmp006.h new file mode 100644 index 0000000000..1d6e07ffdd --- /dev/null +++ b/include/tmp006.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2012 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. + */ + +/* TMP006 temperature sensor module for Chrome EC */ + +#ifndef __CROS_EC_TMP006_H +#define __CROS_EC_TMP006_H + +#define TMP006_ADDR(PORT,REG) ((PORT << 16) + REG) +#define TMP006_PORT(ADDR) (ADDR >> 16) +#define TMP006_REG(ADDR) (ADDR & 0xffff) + +struct tmp006_t { + const char* name; + /* I2C address formed by TMP006_ADDR macro. */ + int addr; +}; + +/* Poll all TMP006 sensors. Return 0 on success. */ +int tmp006_poll(void); + +/* Get the last polled value of a sensor. Return temperature in K. + * The low bit in idx indicate whether to read die temperature or + * object temperature. The other bits serve as internal index to tmp006 + * module. */ +int tmp006_get_val(int idx); + +#endif /* __CROS_EC_TMP006_H */ |