summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2018-06-12 15:18:35 -0600
committerDaisuke Nojiri <dnojiri@chromium.org>2018-06-21 18:08:22 -0700
commit331b1a021b0e8951381621875cfe0d89a6682e02 (patch)
tree58bbfc4f782a39b07cd7eb21eba2e3d4871399e5 /driver
parenta0b57570d46493288bac47e5095a74bfccf775bb (diff)
downloadchrome-ec-331b1a021b0e8951381621875cfe0d89a6682e02.tar.gz
thermistor: move thermistor tables into common code
The exact same 2 lookup tables are in multiple board files. We seem to reuse the 2 thermistor circuit enough that we should single source them in a common location. BRANCH=none BUG=none TEST=yorp sensors still function properly Change-Id: Ic393c609c78c8a51c55a67b639c1fb9e6c387d8a Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1100943 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Furquan Shaikh <furquan@chromium.org> Reviewed-by: Justin TerAvest <teravest@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/build.mk1
-rw-r--r--driver/temp_sensor/thermistor.c147
-rw-r--r--driver/temp_sensor/thermistor.h42
-rw-r--r--driver/temp_sensor/thermistor_ncp15wb.c52
4 files changed, 188 insertions, 54 deletions
diff --git a/driver/build.mk b/driver/build.mk
index 68a412423d..230ca34af3 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -94,6 +94,7 @@ driver-$(CONFIG_TOUCHPAD_ELAN)+=touchpad_elan.o
driver-$(CONFIG_TOUCHPAD_ST)+=touchpad_st.o
# Thermistors
+driver-$(CONFIG_THERMISTOR)+=temp_sensor/thermistor.o
driver-$(CONFIG_THERMISTOR_NCP15WB)+=temp_sensor/thermistor_ncp15wb.o
# Type-C port controller (TCPC) drivers
diff --git a/driver/temp_sensor/thermistor.c b/driver/temp_sensor/thermistor.c
new file mode 100644
index 0000000000..d9c70f7386
--- /dev/null
+++ b/driver/temp_sensor/thermistor.c
@@ -0,0 +1,147 @@
+/* Copyright 2018 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.
+ */
+
+/* Common thermistor code for Chrome EC */
+
+#include "adc.h"
+#include "common.h"
+#include "thermistor.h"
+#include "util.h"
+
+int thermistor_linear_interpolate(uint16_t mv,
+ const struct thermistor_info *info)
+{
+ const struct thermistor_data_pair *data = info->data;
+ int v_high = 0, v_low = 0, t_low, t_high, num_steps;
+ int head, tail, mid = 0;
+
+ /* We need at least two points to form a line. */
+ ASSERT(info->num_pairs >= 2);
+
+ /*
+ * If input value is out of bounds return the lowest or highest
+ * value in the data sets provided.
+ */
+ if (mv > data[0].mv * info->scaling_factor)
+ return data[0].temp;
+ else if (mv < data[info->num_pairs - 1].mv * info->scaling_factor)
+ return data[info->num_pairs - 1].temp;
+
+ head = 0;
+ tail = info->num_pairs - 1;
+ while (head != tail) {
+ mid = (head + tail) / 2;
+ v_high = data[mid].mv * info->scaling_factor;
+ v_low = data[mid + 1].mv * info->scaling_factor;
+
+ if ((mv <= v_high) && (mv >= v_low))
+ break;
+ else if (mv > v_high)
+ tail = mid;
+ else if (mv < v_low)
+ head = mid + 1;
+ }
+
+ t_low = data[mid].temp;
+ t_high = data[mid + 1].temp;
+
+ /*
+ * The obvious way of doing this is to figure out how many mV per
+ * degree are in between the two points (mv_per_deg_c), and then how
+ * many of those exist between the input voltage and voltage of
+ * lower temperature :
+ * 1. mv_per_deg_c = (v_high - v_low) / (t_high - t_low)
+ * 2. num_steps = (v_high - mv) / mv_per_deg_c
+ * 3. result = t_low + num_steps
+ *
+ * Combine #1 and #2 to mitigate precision loss due to integer division.
+ */
+ num_steps = ((v_high - mv) * (t_high - t_low)) / (v_high - v_low);
+ return t_low + num_steps;
+}
+
+#ifdef CONFIG_STEINHART_HART_3V3_51K1_47K_4050B
+/*
+ * Data derived from Steinhart-Hart equation in a resistor divider circuit with
+ * Vdd=3300mV, R = 51.1Kohm, and thermistor (B = 4050, T0 = 298.15 K, nominal
+ * resistance (R0) = 47Kohm).
+ */
+#define THERMISTOR_SCALING_FACTOR_51_47 11
+static const struct thermistor_data_pair thermistor_data_51_47[] = {
+ { 2512 / THERMISTOR_SCALING_FACTOR_51_47, 0 },
+ { 2158 / THERMISTOR_SCALING_FACTOR_51_47, 10 },
+ { 1772 / THERMISTOR_SCALING_FACTOR_51_47, 20 },
+ { 1398 / THERMISTOR_SCALING_FACTOR_51_47, 30 },
+ { 1070 / THERMISTOR_SCALING_FACTOR_51_47, 40 },
+ { 803 / THERMISTOR_SCALING_FACTOR_51_47, 50 },
+ { 597 / THERMISTOR_SCALING_FACTOR_51_47, 60 },
+ { 443 / THERMISTOR_SCALING_FACTOR_51_47, 70 },
+ { 329 / THERMISTOR_SCALING_FACTOR_51_47, 80 },
+ { 285 / THERMISTOR_SCALING_FACTOR_51_47, 85 },
+ { 247 / THERMISTOR_SCALING_FACTOR_51_47, 90 },
+ { 214 / THERMISTOR_SCALING_FACTOR_51_47, 95 },
+ { 187 / THERMISTOR_SCALING_FACTOR_51_47, 100 },
+};
+
+static const struct thermistor_info thermistor_info_51_47 = {
+ .scaling_factor = THERMISTOR_SCALING_FACTOR_51_47,
+ .num_pairs = ARRAY_SIZE(thermistor_data_51_47),
+ .data = thermistor_data_51_47,
+};
+
+int get_temp_3v3_51k1_47k_4050b(int idx_adc, int *temp_ptr)
+{
+ int mv = adc_read_channel(idx_adc);
+
+ if (mv < 0)
+ return EC_ERROR_UNKNOWN;
+
+ *temp_ptr = thermistor_linear_interpolate(mv, &thermistor_info_51_47);
+ *temp_ptr = C_TO_K(*temp_ptr);
+ return EC_SUCCESS;
+}
+#endif /* CONFIG_STEINHART_HART_3V3_51K1_47K_4050B */
+
+#ifdef CONFIG_STEINHART_HART_3V3_13K7_47K_4050B
+/*
+ * Data derived from Steinhart-Hart equation in a resistor divider circuit with
+ * Vdd=3300mV, R = 13.7Kohm, and thermistor (B = 4050, T0 = 298.15 K, nominal
+ * resistance (R0) = 47Kohm).
+ */
+#define THERMISTOR_SCALING_FACTOR_13_47 13
+static const struct thermistor_data_pair thermistor_data_13_47[] = {
+ { 3044 / THERMISTOR_SCALING_FACTOR_13_47, 0 },
+ { 2890 / THERMISTOR_SCALING_FACTOR_13_47, 10 },
+ { 2680 / THERMISTOR_SCALING_FACTOR_13_47, 20 },
+ { 2418 / THERMISTOR_SCALING_FACTOR_13_47, 30 },
+ { 2117 / THERMISTOR_SCALING_FACTOR_13_47, 40 },
+ { 1800 / THERMISTOR_SCALING_FACTOR_13_47, 50 },
+ { 1490 / THERMISTOR_SCALING_FACTOR_13_47, 60 },
+ { 1208 / THERMISTOR_SCALING_FACTOR_13_47, 70 },
+ { 966 / THERMISTOR_SCALING_FACTOR_13_47, 80 },
+ { 860 / THERMISTOR_SCALING_FACTOR_13_47, 85 },
+ { 766 / THERMISTOR_SCALING_FACTOR_13_47, 90 },
+ { 679 / THERMISTOR_SCALING_FACTOR_13_47, 95 },
+ { 603 / THERMISTOR_SCALING_FACTOR_13_47, 100 },
+};
+
+static const struct thermistor_info thermistor_info_13_47 = {
+ .scaling_factor = THERMISTOR_SCALING_FACTOR_13_47,
+ .num_pairs = ARRAY_SIZE(thermistor_data_13_47),
+ .data = thermistor_data_13_47,
+};
+
+int get_temp_3v3_13k7_47k_4050b(int idx_adc, int *temp_ptr)
+{
+ int mv = adc_read_channel(idx_adc);
+
+ if (mv < 0)
+ return EC_ERROR_UNKNOWN;
+
+ *temp_ptr = thermistor_linear_interpolate(mv, &thermistor_info_13_47);
+ *temp_ptr = C_TO_K(*temp_ptr);
+ return EC_SUCCESS;
+}
+#endif /* CONFIG_STEINHART_HART_3V3_13K7_47K_4050B */
diff --git a/driver/temp_sensor/thermistor.h b/driver/temp_sensor/thermistor.h
index af3ea398c8..49edee5451 100644
--- a/driver/temp_sensor/thermistor.h
+++ b/driver/temp_sensor/thermistor.h
@@ -33,7 +33,7 @@ struct thermistor_info {
};
/**
- * @brief Calculate temperature using linear interpolation of data points.
+ * Calculate temperature using linear interpolation of data points.
*
* Given a set of datapoints, the algorithm will calculate the "step" in
* between each one in order to interpolate missing entries.
@@ -44,8 +44,9 @@ struct thermistor_info {
* @return temperature in C
*/
int thermistor_linear_interpolate(uint16_t mv,
- const struct thermistor_info *info);
+ const struct thermistor_info *info);
+#ifdef CONFIG_THERMISTOR_NCP15WB
/**
* ncp15wb temperature conversion routine.
*
@@ -54,5 +55,42 @@ int thermistor_linear_interpolate(uint16_t mv,
* @return temperature in C.
*/
int ncp15wb_calculate_temp(uint16_t adc);
+#endif /* CONFIG_THERMISTOR_NCP15WB */
+
+#ifdef CONFIG_STEINHART_HART_3V3_13K7_47K_4050B
+/**
+ * Reads the specified ADC channel and uses a lookup table and interpolation to
+ * return a temperature in degrees K.
+ *
+ * The lookup table is based off of a resistor divider circuit on 3.3V with a
+ * 13.7K resistor in series with a thermistor with nominal value of 47K (at 25C)
+ * and a B (25/100) value of 4050.
+ *
+ * @param idx_adc The idx value from the temp_sensor_t struct, which is
+ * the ADC channel to read and convert to degrees K
+ * @param temp_ptr Destination for temperature (in degrees K)
+ *
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int get_temp_3v3_13k7_47k_4050b(int idx_adc, int *temp_ptr);
+#endif
+
+#ifdef CONFIG_STEINHART_HART_3V3_51K1_47K_4050B
+/**
+ * Reads the specified ADC channel and uses a lookup table and interpolation to
+ * return a temperature in degrees K.
+ *
+ * The lookup table is based off of a resistor divider circuit on 3.3V with a
+ * 51.1K resistor in series with a thermistor with nominal value of 47K (at 25C)
+ * and a B (25/100) value of 4050.
+ *
+ * @param idx_adc The idx value from the temp_sensor_t struct, which is
+ * the ADC channel to read and convert to degrees K
+ * @param temp_ptr Destination for temperature (in degrees K)
+ *
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int get_temp_3v3_51k1_47k_4050b(int idx_adc, int *temp_ptr);
+#endif
#endif /* __CROS_EC_TEMP_SENSOR_THERMISTOR_NCP15WB_H */
diff --git a/driver/temp_sensor/thermistor_ncp15wb.c b/driver/temp_sensor/thermistor_ncp15wb.c
index dae8251575..51e884ed35 100644
--- a/driver/temp_sensor/thermistor_ncp15wb.c
+++ b/driver/temp_sensor/thermistor_ncp15wb.c
@@ -98,55 +98,3 @@ int ncp15wb_calculate_temp(uint16_t adc)
return temp;
}
-
-int thermistor_linear_interpolate(uint16_t mv,
- const struct thermistor_info *info)
-{
- const struct thermistor_data_pair *data = info->data;
- int v_high = 0, v_low = 0, t_low, t_high, num_steps;
- int head, tail, mid = 0;
-
- /* We need at least two points to form a line. */
- ASSERT(info->num_pairs >= 2);
-
- /*
- * If input value is out of bounds return the lowest or highest
- * value in the data sets provided.
- */
- if (mv > data[0].mv * info->scaling_factor)
- return data[0].temp;
- else if (mv < data[info->num_pairs - 1].mv * info->scaling_factor)
- return data[info->num_pairs - 1].temp;
-
- head = 0;
- tail = info->num_pairs - 1;
- while (head != tail) {
- mid = (head + tail) / 2;
- v_high = data[mid].mv * info->scaling_factor;
- v_low = data[mid + 1].mv * info->scaling_factor;
-
- if ((mv <= v_high) && (mv >= v_low))
- break;
- else if (mv > v_high)
- tail = mid;
- else if (mv < v_low)
- head = mid + 1;
- }
-
- t_low = data[mid].temp;
- t_high = data[mid + 1].temp;
-
- /*
- * The obvious way of doing this is to figure out how many mV per
- * degree are in between the two points (mv_per_deg_c), and then how
- * many of those exist between the input voltage and voltage of
- * lower temperature :
- * 1. mv_per_deg_c = (v_high - v_low) / (t_high - t_low)
- * 2. num_steps = (v_high - mv) / mv_per_deg_c
- * 3. result = t_low + num_steps
- *
- * Combine #1 and #2 to mitigate precision loss due to integer division.
- */
- num_steps = ((v_high - mv) * (t_high - t_low)) / (v_high - v_low);
- return t_low + num_steps;
-}