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 @@
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/units.h>
#include <linux/workqueue.h>
#include <acpi/battery.h>
......@@ -6128,12 +6129,15 @@ enum thermal_access_mode {
TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
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 */
};
enum { /* TPACPI_THERMAL_TPEC_* */
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_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_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
......@@ -6146,8 +6150,22 @@ struct ibm_thermal_sensors_struct {
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 bool thermal_use_labels;
static bool thermal_with_ns_address; /* Non-standard thermal reg address */
/* Function to check thermal read mode */
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))
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;
for (i = 0; i < 8; i++) {
if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
......@@ -6248,6 +6276,20 @@ static int thermal_get_sensor(int idx, s32 *value)
}
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:
if (idx <= 7) {
snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
......@@ -6289,6 +6331,8 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
n = 16;
else if (thermal_read_mode == TPACPI_THERMAL_TPEC_12)
n = 12;
else
n = 8;
......@@ -6389,18 +6433,36 @@ static struct attribute *thermal_temp_input_attr[] = {
NULL
};
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
static umode_t thermal_attr_is_visible(struct kobject *kobj,
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;
if (attr == THERMAL_ATTRS(8) || attr == THERMAL_ATTRS(9) ||
attr == THERMAL_ATTRS(10) || attr == THERMAL_ATTRS(11) ||
attr == THERMAL_ATTRS(12) || attr == THERMAL_ATTRS(13) ||
attr == THERMAL_ATTRS(14) || attr == THERMAL_ATTRS(15)) {
if (thermal_read_mode != TPACPI_THERMAL_TPEC_16)
case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT:
case TPACPI_THERMAL_TPEC_8:
if (idx >= 8)
return 0;
break;
case TPACPI_THERMAL_TPEC_12:
if (idx >= 12)
return 0;
break;
default:
break;
}
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