Commit 301c1904 authored by Vishnu Sankar's avatar Vishnu Sankar Committed by Ilpo Järvinen

platform/x86: thinkpad_acpi: Fix to correct wrong temp reporting on some ThinkPads

Added non-standard thermal register's support for some ThinkPads.

Some of the Thinkpads use a non-standard ECFW which has different
thermal register addresses. This is a fix to correct the wrong temperature
reporting on those systems.

Tested on Lenovo ThinkPad L13 Yoga Gen2.
Suggested-by: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: default avatarVishnu Sankar <vishnuocv@gmail.com>
Link: https://lore.kernel.org/r/20240215134102.25118-2-vishnuocv@gmail.comReviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
parent ee8b738e
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/units.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <acpi/battery.h> #include <acpi/battery.h>
...@@ -6128,12 +6129,15 @@ enum thermal_access_mode { ...@@ -6128,12 +6129,15 @@ enum thermal_access_mode {
TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
TPACPI_THERMAL_TPEC_12, /* Use ACPI EC regs, 12 sensors */
TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
}; };
enum { /* TPACPI_THERMAL_TPEC_* */ enum { /* TPACPI_THERMAL_TPEC_* */
TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
TP_EC_THERMAL_TMP0_NS = 0xA8, /* ACPI EC Non-Standard regs TMP 0..7 */
TP_EC_THERMAL_TMP8_NS = 0xB8, /* ACPI EC Non-standard regs TMP 8..11 */
TP_EC_FUNCREV = 0xEF, /* ACPI EC Functional revision */ TP_EC_FUNCREV = 0xEF, /* ACPI EC Functional revision */
TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
...@@ -6146,8 +6150,22 @@ struct ibm_thermal_sensors_struct { ...@@ -6146,8 +6150,22 @@ struct ibm_thermal_sensors_struct {
s32 temp[TPACPI_MAX_THERMAL_SENSORS]; s32 temp[TPACPI_MAX_THERMAL_SENSORS];
}; };
static const struct tpacpi_quirk thermal_quirk_table[] __initconst = {
/* Non-standard address for thermal registers on some ThinkPads */
TPACPI_Q_LNV3('R', '1', 'F', true), /* L13 Yoga Gen 2 */
TPACPI_Q_LNV3('N', '2', 'U', true), /* X13 Yoga Gen 2*/
TPACPI_Q_LNV3('R', '0', 'R', true), /* L380 */
TPACPI_Q_LNV3('R', '1', '5', true), /* L13 Yoga Gen 1*/
TPACPI_Q_LNV3('R', '1', '0', true), /* L390 */
TPACPI_Q_LNV3('N', '2', 'L', true), /* X13 Yoga Gen 1*/
TPACPI_Q_LNV3('R', '0', 'T', true), /* 11e Gen5 GL*/
TPACPI_Q_LNV3('R', '1', 'D', true), /* 11e Gen5 GL-R*/
TPACPI_Q_LNV3('R', '0', 'V', true), /* 11e Gen5 KL-Y*/
};
static enum thermal_access_mode thermal_read_mode; static enum thermal_access_mode thermal_read_mode;
static bool thermal_use_labels; static bool thermal_use_labels;
static bool thermal_with_ns_address; /* Non-standard thermal reg address */
/* Function to check thermal read mode */ /* Function to check thermal read mode */
static enum thermal_access_mode __init thermal_read_mode_check(void) static enum thermal_access_mode __init thermal_read_mode_check(void)
...@@ -6172,6 +6190,16 @@ static enum thermal_access_mode __init thermal_read_mode_check(void) ...@@ -6172,6 +6190,16 @@ static enum thermal_access_mode __init thermal_read_mode_check(void)
if (!acpi_ec_read(TP_EC_FUNCREV, &ver)) if (!acpi_ec_read(TP_EC_FUNCREV, &ver))
pr_warn("Thinkpad ACPI EC unable to access EC version\n"); pr_warn("Thinkpad ACPI EC unable to access EC version\n");
/* Quirks to check non-standard EC */
thermal_with_ns_address = tpacpi_check_quirks(thermal_quirk_table,
ARRAY_SIZE(thermal_quirk_table));
/* Support for Thinkpads with non-standard address */
if (thermal_with_ns_address) {
pr_info("ECFW with non-standard thermal registers found\n");
return TPACPI_THERMAL_TPEC_12;
}
ta1 = ta2 = 0; ta1 = ta2 = 0;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) { if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
...@@ -6248,6 +6276,20 @@ static int thermal_get_sensor(int idx, s32 *value) ...@@ -6248,6 +6276,20 @@ static int thermal_get_sensor(int idx, s32 *value)
} }
break; break;
/* The Non-standard EC uses 12 Thermal areas */
case TPACPI_THERMAL_TPEC_12:
if (idx >= 12)
return -EINVAL;
t = idx < 8 ? TP_EC_THERMAL_TMP0_NS + idx :
TP_EC_THERMAL_TMP8_NS + (idx - 8);
if (!acpi_ec_read(t, &tmp))
return -EIO;
*value = tmp * MILLIDEGREE_PER_DEGREE;
return 0;
case TPACPI_THERMAL_ACPI_UPDT: case TPACPI_THERMAL_ACPI_UPDT:
if (idx <= 7) { if (idx <= 7) {
snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
...@@ -6289,6 +6331,8 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) ...@@ -6289,6 +6331,8 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
n = 16; n = 16;
else if (thermal_read_mode == TPACPI_THERMAL_TPEC_12)
n = 12;
else else
n = 8; n = 8;
...@@ -6389,18 +6433,36 @@ static struct attribute *thermal_temp_input_attr[] = { ...@@ -6389,18 +6433,36 @@ static struct attribute *thermal_temp_input_attr[] = {
NULL NULL
}; };
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
static umode_t thermal_attr_is_visible(struct kobject *kobj, static umode_t thermal_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n) struct attribute *attr, int n)
{ {
if (thermal_read_mode == TPACPI_THERMAL_NONE) struct device_attribute *dev_attr = to_dev_attr(attr);
struct sensor_device_attribute *sensor_attr =
to_sensor_dev_attr(dev_attr);
int idx = sensor_attr->index;
switch (thermal_read_mode) {
case TPACPI_THERMAL_NONE:
return 0; return 0;
if (attr == THERMAL_ATTRS(8) || attr == THERMAL_ATTRS(9) || case TPACPI_THERMAL_ACPI_TMP07:
attr == THERMAL_ATTRS(10) || attr == THERMAL_ATTRS(11) || case TPACPI_THERMAL_ACPI_UPDT:
attr == THERMAL_ATTRS(12) || attr == THERMAL_ATTRS(13) || case TPACPI_THERMAL_TPEC_8:
attr == THERMAL_ATTRS(14) || attr == THERMAL_ATTRS(15)) { if (idx >= 8)
if (thermal_read_mode != TPACPI_THERMAL_TPEC_16)
return 0; return 0;
break;
case TPACPI_THERMAL_TPEC_12:
if (idx >= 12)
return 0;
break;
default:
break;
} }
return attr->mode; return attr->mode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment