···5555ifdef CONFIG_ACPI_VIDEO5656acpi-y += video_detect.o5757endif5858+acpi-y += acpi_lpat.o58595960# These are (potentially) separate modules6061
+161
drivers/acpi/acpi_lpat.c
···11+/*22+ * acpi_lpat.c - LPAT table processing functions33+ *44+ * Copyright (C) 2015 Intel Corporation. All rights reserved.55+ *66+ * This program is free software; you can redistribute it and/or77+ * modify it under the terms of the GNU General Public License version88+ * 2 as published by the Free Software Foundation.99+ *1010+ * This program is distributed in the hope that it will be useful,1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313+ * GNU General Public License for more details.1414+ */1515+1616+#include <linux/module.h>1717+#include <linux/acpi.h>1818+#include <acpi/acpi_lpat.h>1919+2020+/**2121+ * acpi_lpat_raw_to_temp(): Return temperature from raw value through2222+ * LPAT conversion table2323+ *2424+ * @lpat_table: the temperature_raw mapping table structure2525+ * @raw: the raw value, used as a key to get the temerature from the2626+ * above mapping table2727+ *2828+ * A positive converted temperarure value will be returned on success,2929+ * a negative errno will be returned in error cases.3030+ */3131+int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,3232+ int raw)3333+{3434+ int i, delta_temp, delta_raw, temp;3535+ struct acpi_lpat *lpat = lpat_table->lpat;3636+3737+ for (i = 0; i < lpat_table->lpat_count - 1; i++) {3838+ if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||3939+ (raw <= lpat[i].raw && raw >= lpat[i+1].raw))4040+ break;4141+ }4242+4343+ if (i == lpat_table->lpat_count - 1)4444+ return -ENOENT;4545+4646+ delta_temp = lpat[i+1].temp - lpat[i].temp;4747+ delta_raw = lpat[i+1].raw - lpat[i].raw;4848+ temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;4949+5050+ return temp;5151+}5252+EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp);5353+5454+/**5555+ * acpi_lpat_temp_to_raw(): Return raw value from temperature through5656+ * LPAT conversion table5757+ *5858+ * @lpat: the temperature_raw mapping table5959+ * @temp: the temperature, used as a key to get the raw value from the6060+ * above mapping table6161+ *6262+ * A positive converted temperature value will be returned on success,6363+ * a negative errno will be returned in error cases.6464+ */6565+int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,6666+ int temp)6767+{6868+ int i, delta_temp, delta_raw, raw;6969+ struct acpi_lpat *lpat = lpat_table->lpat;7070+7171+ for (i = 0; i < lpat_table->lpat_count - 1; i++) {7272+ if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)7373+ break;7474+ }7575+7676+ if (i == lpat_table->lpat_count - 1)7777+ return -ENOENT;7878+7979+ delta_temp = lpat[i+1].temp - lpat[i].temp;8080+ delta_raw = lpat[i+1].raw - lpat[i].raw;8181+ raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;8282+8383+ return raw;8484+}8585+EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw);8686+8787+/**8888+ * acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present.8989+ *9090+ * @handle: Handle to acpi device9191+ *9292+ * Parse LPAT table to a struct of type acpi_lpat_table. On success9393+ * it returns a pointer to newly allocated table. This table must9494+ * be freed by the caller when finished processing, using a call to9595+ * acpi_lpat_free_conversion_table.9696+ */9797+struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle9898+ handle)9999+{100100+ struct acpi_lpat_conversion_table *lpat_table = NULL;101101+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };102102+ union acpi_object *obj_p, *obj_e;103103+ int *lpat, i;104104+ acpi_status status;105105+106106+ status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);107107+ if (ACPI_FAILURE(status))108108+ return NULL;109109+110110+ obj_p = (union acpi_object *)buffer.pointer;111111+ if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||112112+ (obj_p->package.count % 2) || (obj_p->package.count < 4))113113+ goto out;114114+115115+ lpat = kcalloc(obj_p->package.count, sizeof(int), GFP_KERNEL);116116+ if (!lpat)117117+ goto out;118118+119119+ for (i = 0; i < obj_p->package.count; i++) {120120+ obj_e = &obj_p->package.elements[i];121121+ if (obj_e->type != ACPI_TYPE_INTEGER) {122122+ kfree(lpat);123123+ goto out;124124+ }125125+ lpat[i] = (s64)obj_e->integer.value;126126+ }127127+128128+ lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL);129129+ if (!lpat_table) {130130+ kfree(lpat);131131+ goto out;132132+ }133133+134134+ lpat_table->lpat = (struct acpi_lpat *)lpat;135135+ lpat_table->lpat_count = obj_p->package.count / 2;136136+137137+out:138138+ kfree(buffer.pointer);139139+ return lpat_table;140140+}141141+EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table);142142+143143+/**144144+ * acpi_lpat_free_conversion_table(): Free LPAT table.145145+ *146146+ * @lpat_table: the temperature_raw mapping table structure147147+ *148148+ * Frees the LPAT table previously allocated by a call to149149+ * acpi_lpat_get_conversion_table.150150+ */151151+void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table152152+ *lpat_table)153153+{154154+ if (lpat_table) {155155+ kfree(lpat_table->lpat);156156+ kfree(lpat_table);157157+ }158158+}159159+EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table);160160+161161+MODULE_LICENSE("GPL");
+18-115
drivers/acpi/pmic/intel_pmic.c
···1616#include <linux/module.h>1717#include <linux/acpi.h>1818#include <linux/regmap.h>1919+#include <acpi/acpi_lpat.h>1920#include "intel_pmic.h"20212122#define PMIC_POWER_OPREGION_ID 0x8d2223#define PMIC_THERMAL_OPREGION_ID 0x8c23242424-struct acpi_lpat {2525- int temp;2626- int raw;2727-};2828-2925struct intel_pmic_opregion {3026 struct mutex lock;3131- struct acpi_lpat *lpat;3232- int lpat_count;2727+ struct acpi_lpat_conversion_table *lpat_table;3328 struct regmap *regmap;3429 struct intel_pmic_opregion_data *data;3530};···4348 }4449 }4550 return -ENOENT;4646-}4747-4848-/**4949- * raw_to_temp(): Return temperature from raw value through LPAT table5050- *5151- * @lpat: the temperature_raw mapping table5252- * @count: the count of the above mapping table5353- * @raw: the raw value, used as a key to get the temerature from the5454- * above mapping table5555- *5656- * A positive value will be returned on success, a negative errno will5757- * be returned in error cases.5858- */5959-static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)6060-{6161- int i, delta_temp, delta_raw, temp;6262-6363- for (i = 0; i < count - 1; i++) {6464- if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||6565- (raw <= lpat[i].raw && raw >= lpat[i+1].raw))6666- break;6767- }6868-6969- if (i == count - 1)7070- return -ENOENT;7171-7272- delta_temp = lpat[i+1].temp - lpat[i].temp;7373- delta_raw = lpat[i+1].raw - lpat[i].raw;7474- temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;7575-7676- return temp;7777-}7878-7979-/**8080- * temp_to_raw(): Return raw value from temperature through LPAT table8181- *8282- * @lpat: the temperature_raw mapping table8383- * @count: the count of the above mapping table8484- * @temp: the temperature, used as a key to get the raw value from the8585- * above mapping table8686- *8787- * A positive value will be returned on success, a negative errno will8888- * be returned in error cases.8989- */9090-static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)9191-{9292- int i, delta_temp, delta_raw, raw;9393-9494- for (i = 0; i < count - 1; i++) {9595- if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)9696- break;9797- }9898-9999- if (i == count - 1)100100- return -ENOENT;101101-102102- delta_temp = lpat[i+1].temp - lpat[i].temp;103103- delta_raw = lpat[i+1].raw - lpat[i].raw;104104- raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;105105-106106- return raw;107107-}108108-109109-static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,110110- acpi_handle handle, struct device *dev)111111-{112112- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };113113- union acpi_object *obj_p, *obj_e;114114- int *lpat, i;115115- acpi_status status;116116-117117- status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);118118- if (ACPI_FAILURE(status))119119- return;120120-121121- obj_p = (union acpi_object *)buffer.pointer;122122- if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||123123- (obj_p->package.count % 2) || (obj_p->package.count < 4))124124- goto out;125125-126126- lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,127127- GFP_KERNEL);128128- if (!lpat)129129- goto out;130130-131131- for (i = 0; i < obj_p->package.count; i++) {132132- obj_e = &obj_p->package.elements[i];133133- if (obj_e->type != ACPI_TYPE_INTEGER) {134134- devm_kfree(dev, lpat);135135- goto out;136136- }137137- lpat[i] = (s64)obj_e->integer.value;138138- }139139-140140- opregion->lpat = (struct acpi_lpat *)lpat;141141- opregion->lpat_count = obj_p->package.count / 2;142142-143143-out:144144- kfree(buffer.pointer);14551}1465214753static acpi_status intel_pmic_power_handler(u32 function,···88192 if (raw_temp < 0)89193 return raw_temp;901949191- if (!opregion->lpat) {195195+ if (!opregion->lpat_table) {92196 *value = raw_temp;93197 return 0;94198 }951999696- temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp);200200+ temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp);97201 if (temp < 0)98202 return temp;99203···119223 if (!opregion->data->update_aux)120224 return -ENXIO;121225122122- if (opregion->lpat) {123123- raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,124124- *value);226226+ if (opregion->lpat_table) {227227+ raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value);125228 if (raw_temp < 0)126229 return raw_temp;127230 } else {···209314{210315 acpi_status status;211316 struct intel_pmic_opregion *opregion;317317+ int ret;212318213319 if (!dev || !regmap || !d)214320 return -EINVAL;···223327224328 mutex_init(&opregion->lock);225329 opregion->regmap = regmap;226226- pmic_thermal_lpat(opregion, handle, dev);330330+ opregion->lpat_table = acpi_lpat_get_conversion_table(handle);227331228332 status = acpi_install_address_space_handler(handle,229333 PMIC_POWER_OPREGION_ID,230334 intel_pmic_power_handler,231335 NULL, opregion);232232- if (ACPI_FAILURE(status))233233- return -ENODEV;336336+ if (ACPI_FAILURE(status)) {337337+ ret = -ENODEV;338338+ goto out_error;339339+ }234340235341 status = acpi_install_address_space_handler(handle,236342 PMIC_THERMAL_OPREGION_ID,···241343 if (ACPI_FAILURE(status)) {242344 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,243345 intel_pmic_power_handler);244244- return -ENODEV;346346+ ret = -ENODEV;347347+ goto out_error;245348 }246349247350 opregion->data = d;248351 return 0;352352+353353+out_error:354354+ acpi_lpat_free_conversion_table(opregion->lpat_table);355355+ return ret;249356}250357EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);251358
···11+/*22+ * int340x_thermal_zone.h33+ * Copyright (c) 2015, Intel Corporation.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ */1515+1616+#ifndef __INT340X_THERMAL_ZONE_H__1717+#define __INT340X_THERMAL_ZONE_H__1818+1919+#include <acpi/acpi_lpat.h>2020+2121+#define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 102222+2323+struct active_trip {2424+ unsigned long temp;2525+ int id;2626+ bool valid;2727+};2828+2929+struct int34x_thermal_zone {3030+ struct acpi_device *adev;3131+ struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT];3232+ unsigned long *aux_trips;3333+ int aux_trip_nr;3434+ unsigned long psv_temp;3535+ int psv_trip_id;3636+ unsigned long crt_temp;3737+ int crt_trip_id;3838+ unsigned long hot_temp;3939+ int hot_trip_id;4040+ struct thermal_zone_device *zone;4141+ struct thermal_zone_device_ops *override_ops;4242+ void *priv_data;4343+ struct acpi_lpat_conversion_table *lpat_table;4444+};4545+4646+struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *,4747+ struct thermal_zone_device_ops *override_ops);4848+void int340x_thermal_zone_remove(struct int34x_thermal_zone *);4949+5050+static inline void int340x_thermal_zone_set_priv_data(5151+ struct int34x_thermal_zone *tzone, void *priv_data)5252+{5353+ tzone->priv_data = priv_data;5454+}5555+5656+static inline void *int340x_thermal_zone_get_priv_data(5757+ struct int34x_thermal_zone *tzone)5858+{5959+ return tzone->priv_data;6060+}6161+6262+static inline void int340x_thermal_zone_device_update(6363+ struct int34x_thermal_zone *tzone)6464+{6565+ thermal_zone_device_update(tzone->zone);6666+}6767+6868+#endif
···1818#include <linux/pci.h>1919#include <linux/platform_device.h>2020#include <linux/acpi.h>2121+#include <linux/thermal.h>2222+#include "int340x_thermal_zone.h"21232224/* Broadwell-U/HSB thermal reporting device */2325#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603···4139 struct device *dev;4240 struct acpi_device *adev;4341 struct power_config power_limits[2];4242+ struct int34x_thermal_zone *int340x_zone;4443};45444645enum proc_thermal_emum_mode_type {···120117 .name = "power_limits"121118};122119120120+static int stored_tjmax; /* since it is fixed, we can have local storage */121121+122122+static int get_tjmax(void)123123+{124124+ u32 eax, edx;125125+ u32 val;126126+ int err;127127+128128+ err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);129129+ if (err)130130+ return err;131131+132132+ val = (eax >> 16) & 0xff;133133+ if (val)134134+ return val;135135+136136+ return -EINVAL;137137+}138138+139139+static int read_temp_msr(unsigned long *temp)140140+{141141+ int cpu;142142+ u32 eax, edx;143143+ int err;144144+ unsigned long curr_temp_off = 0;145145+146146+ *temp = 0;147147+148148+ for_each_online_cpu(cpu) {149149+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax,150150+ &edx);151151+ if (err)152152+ goto err_ret;153153+ else {154154+ if (eax & 0x80000000) {155155+ curr_temp_off = (eax >> 16) & 0x7f;156156+ if (!*temp || curr_temp_off < *temp)157157+ *temp = curr_temp_off;158158+ } else {159159+ err = -EINVAL;160160+ goto err_ret;161161+ }162162+ }163163+ }164164+165165+ return 0;166166+err_ret:167167+ return err;168168+}169169+170170+static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone,171171+ unsigned long *temp)172172+{173173+ int ret;174174+175175+ ret = read_temp_msr(temp);176176+ if (!ret)177177+ *temp = (stored_tjmax - *temp) * 1000;178178+179179+ return ret;180180+}181181+182182+static struct thermal_zone_device_ops proc_thermal_local_ops = {183183+ .get_temp = proc_thermal_get_zone_temp,184184+};185185+123186static int proc_thermal_add(struct device *dev,124187 struct proc_thermal_device **priv)125188{···195126 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };196127 union acpi_object *elements, *ppcc;197128 union acpi_object *p;129129+ unsigned long long tmp;130130+ struct thermal_zone_device_ops *ops = NULL;198131 int i;199132 int ret;200133···249178250179 ret = sysfs_create_group(&dev->kobj,251180 &power_limit_attribute_group);181181+ if (ret)182182+ goto free_buffer;183183+184184+ status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp);185185+ if (ACPI_FAILURE(status)) {186186+ /* there is no _TMP method, add local method */187187+ stored_tjmax = get_tjmax();188188+ if (stored_tjmax > 0)189189+ ops = &proc_thermal_local_ops;190190+ }191191+192192+ proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops);193193+ if (IS_ERR(proc_priv->int340x_zone)) {194194+ sysfs_remove_group(&proc_priv->dev->kobj,195195+ &power_limit_attribute_group);196196+ ret = PTR_ERR(proc_priv->int340x_zone);197197+ } else198198+ ret = 0;252199253200free_buffer:254201 kfree(buf.pointer);···276187277188void proc_thermal_remove(struct proc_thermal_device *proc_priv)278189{190190+ int340x_thermal_zone_remove(proc_priv->int340x_zone);279191 sysfs_remove_group(&proc_priv->dev->kobj,280192 &power_limit_attribute_group);281193}
+65
include/acpi/acpi_lpat.h
···11+/*22+ * acpi_lpat.h - LPAT table processing functions33+ *44+ * Copyright (C) 2015 Intel Corporation. All rights reserved.55+ *66+ * This program is free software; you can redistribute it and/or77+ * modify it under the terms of the GNU General Public License version88+ * 2 as published by the Free Software Foundation.99+ *1010+ * This program is distributed in the hope that it will be useful,1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313+ * GNU General Public License for more details.1414+ */1515+1616+#ifndef ACPI_LPAT_H1717+#define ACPI_LPAT_H1818+1919+struct acpi_lpat {2020+ int temp;2121+ int raw;2222+};2323+2424+struct acpi_lpat_conversion_table {2525+ struct acpi_lpat *lpat;2626+ int lpat_count;2727+};2828+2929+#ifdef CONFIG_ACPI3030+3131+int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,3232+ int raw);3333+int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,3434+ int temp);3535+struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle3636+ handle);3737+void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table3838+ *lpat_table);3939+4040+#else4141+static int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,4242+ int raw)4343+{4444+ return 0;4545+}4646+4747+static int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,4848+ int temp)4949+{5050+ return 0;5151+}5252+5353+static struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(5454+ acpi_handle handle)5555+{5656+ return NULL;5757+}5858+5959+static void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table6060+ *lpat_table)6161+{6262+}6363+6464+#endif6565+#endif