diff options
| -rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/acpi/acpi_lpat.c | 161 | ||||
| -rw-r--r-- | drivers/acpi/pmic/intel_pmic.c | 133 | ||||
| -rw-r--r-- | drivers/thermal/int340x_thermal/Makefile | 1 | ||||
| -rw-r--r-- | drivers/thermal/int340x_thermal/int3400_thermal.c | 4 | ||||
| -rw-r--r-- | drivers/thermal/int340x_thermal/int3402_thermal.c | 208 | ||||
| -rw-r--r-- | drivers/thermal/int340x_thermal/int3403_thermal.c | 208 | ||||
| -rw-r--r-- | drivers/thermal/int340x_thermal/int340x_thermal_zone.c | 276 | ||||
| -rw-r--r-- | drivers/thermal/int340x_thermal/int340x_thermal_zone.h | 68 | ||||
| -rw-r--r-- | drivers/thermal/int340x_thermal/processor_thermal_device.c | 92 | ||||
| -rw-r--r-- | drivers/thermal/intel_soc_dts_thermal.c | 46 | ||||
| -rw-r--r-- | drivers/thermal/step_wise.c | 4 | ||||
| -rw-r--r-- | include/acpi/acpi_lpat.h | 65 |
13 files changed, 760 insertions, 507 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index b18cd2151ddb..623b117ad1a2 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
| @@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o | |||
| 55 | ifdef CONFIG_ACPI_VIDEO | 55 | ifdef CONFIG_ACPI_VIDEO |
| 56 | acpi-y += video_detect.o | 56 | acpi-y += video_detect.o |
| 57 | endif | 57 | endif |
| 58 | acpi-y += acpi_lpat.o | ||
| 58 | 59 | ||
| 59 | # These are (potentially) separate modules | 60 | # These are (potentially) separate modules |
| 60 | 61 | ||
diff --git a/drivers/acpi/acpi_lpat.c b/drivers/acpi/acpi_lpat.c new file mode 100644 index 000000000000..feb61c1630eb --- /dev/null +++ b/drivers/acpi/acpi_lpat.c | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | /* | ||
| 2 | * acpi_lpat.c - LPAT table processing functions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2015 Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/acpi.h> | ||
| 18 | #include <acpi/acpi_lpat.h> | ||
| 19 | |||
| 20 | /** | ||
| 21 | * acpi_lpat_raw_to_temp(): Return temperature from raw value through | ||
| 22 | * LPAT conversion table | ||
| 23 | * | ||
| 24 | * @lpat_table: the temperature_raw mapping table structure | ||
| 25 | * @raw: the raw value, used as a key to get the temerature from the | ||
| 26 | * above mapping table | ||
| 27 | * | ||
| 28 | * A positive converted temperarure value will be returned on success, | ||
| 29 | * a negative errno will be returned in error cases. | ||
| 30 | */ | ||
| 31 | int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, | ||
| 32 | int raw) | ||
| 33 | { | ||
| 34 | int i, delta_temp, delta_raw, temp; | ||
| 35 | struct acpi_lpat *lpat = lpat_table->lpat; | ||
| 36 | |||
| 37 | for (i = 0; i < lpat_table->lpat_count - 1; i++) { | ||
| 38 | if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) || | ||
| 39 | (raw <= lpat[i].raw && raw >= lpat[i+1].raw)) | ||
| 40 | break; | ||
| 41 | } | ||
| 42 | |||
| 43 | if (i == lpat_table->lpat_count - 1) | ||
| 44 | return -ENOENT; | ||
| 45 | |||
| 46 | delta_temp = lpat[i+1].temp - lpat[i].temp; | ||
| 47 | delta_raw = lpat[i+1].raw - lpat[i].raw; | ||
| 48 | temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw; | ||
| 49 | |||
| 50 | return temp; | ||
| 51 | } | ||
| 52 | EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * acpi_lpat_temp_to_raw(): Return raw value from temperature through | ||
| 56 | * LPAT conversion table | ||
| 57 | * | ||
| 58 | * @lpat: the temperature_raw mapping table | ||
| 59 | * @temp: the temperature, used as a key to get the raw value from the | ||
| 60 | * above mapping table | ||
| 61 | * | ||
| 62 | * A positive converted temperature value will be returned on success, | ||
| 63 | * a negative errno will be returned in error cases. | ||
| 64 | */ | ||
| 65 | int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, | ||
| 66 | int temp) | ||
| 67 | { | ||
| 68 | int i, delta_temp, delta_raw, raw; | ||
| 69 | struct acpi_lpat *lpat = lpat_table->lpat; | ||
| 70 | |||
| 71 | for (i = 0; i < lpat_table->lpat_count - 1; i++) { | ||
| 72 | if (temp >= lpat[i].temp && temp <= lpat[i+1].temp) | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (i == lpat_table->lpat_count - 1) | ||
| 77 | return -ENOENT; | ||
| 78 | |||
| 79 | delta_temp = lpat[i+1].temp - lpat[i].temp; | ||
| 80 | delta_raw = lpat[i+1].raw - lpat[i].raw; | ||
| 81 | raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp; | ||
| 82 | |||
| 83 | return raw; | ||
| 84 | } | ||
| 85 | EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw); | ||
| 86 | |||
| 87 | /** | ||
| 88 | * acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present. | ||
| 89 | * | ||
| 90 | * @handle: Handle to acpi device | ||
| 91 | * | ||
| 92 | * Parse LPAT table to a struct of type acpi_lpat_table. On success | ||
| 93 | * it returns a pointer to newly allocated table. This table must | ||
| 94 | * be freed by the caller when finished processing, using a call to | ||
| 95 | * acpi_lpat_free_conversion_table. | ||
| 96 | */ | ||
| 97 | struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle | ||
| 98 | handle) | ||
| 99 | { | ||
| 100 | struct acpi_lpat_conversion_table *lpat_table = NULL; | ||
| 101 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 102 | union acpi_object *obj_p, *obj_e; | ||
| 103 | int *lpat, i; | ||
| 104 | acpi_status status; | ||
| 105 | |||
| 106 | status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer); | ||
| 107 | if (ACPI_FAILURE(status)) | ||
| 108 | return NULL; | ||
| 109 | |||
| 110 | obj_p = (union acpi_object *)buffer.pointer; | ||
| 111 | if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) || | ||
| 112 | (obj_p->package.count % 2) || (obj_p->package.count < 4)) | ||
| 113 | goto out; | ||
| 114 | |||
| 115 | lpat = kcalloc(obj_p->package.count, sizeof(int), GFP_KERNEL); | ||
| 116 | if (!lpat) | ||
| 117 | goto out; | ||
| 118 | |||
| 119 | for (i = 0; i < obj_p->package.count; i++) { | ||
| 120 | obj_e = &obj_p->package.elements[i]; | ||
| 121 | if (obj_e->type != ACPI_TYPE_INTEGER) { | ||
| 122 | kfree(lpat); | ||
| 123 | goto out; | ||
| 124 | } | ||
| 125 | lpat[i] = (s64)obj_e->integer.value; | ||
| 126 | } | ||
| 127 | |||
| 128 | lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL); | ||
| 129 | if (!lpat_table) { | ||
| 130 | kfree(lpat); | ||
| 131 | goto out; | ||
| 132 | } | ||
| 133 | |||
| 134 | lpat_table->lpat = (struct acpi_lpat *)lpat; | ||
| 135 | lpat_table->lpat_count = obj_p->package.count / 2; | ||
| 136 | |||
| 137 | out: | ||
| 138 | kfree(buffer.pointer); | ||
| 139 | return lpat_table; | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table); | ||
| 142 | |||
| 143 | /** | ||
| 144 | * acpi_lpat_free_conversion_table(): Free LPAT table. | ||
| 145 | * | ||
| 146 | * @lpat_table: the temperature_raw mapping table structure | ||
| 147 | * | ||
| 148 | * Frees the LPAT table previously allocated by a call to | ||
| 149 | * acpi_lpat_get_conversion_table. | ||
| 150 | */ | ||
| 151 | void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table | ||
| 152 | *lpat_table) | ||
| 153 | { | ||
| 154 | if (lpat_table) { | ||
| 155 | kfree(lpat_table->lpat); | ||
| 156 | kfree(lpat_table); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table); | ||
| 160 | |||
| 161 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c index a732e5d7e322..bd772cd56494 100644 --- a/drivers/acpi/pmic/intel_pmic.c +++ b/drivers/acpi/pmic/intel_pmic.c | |||
| @@ -16,20 +16,15 @@ | |||
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
| 18 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
| 19 | #include <acpi/acpi_lpat.h> | ||
| 19 | #include "intel_pmic.h" | 20 | #include "intel_pmic.h" |
| 20 | 21 | ||
| 21 | #define PMIC_POWER_OPREGION_ID 0x8d | 22 | #define PMIC_POWER_OPREGION_ID 0x8d |
| 22 | #define PMIC_THERMAL_OPREGION_ID 0x8c | 23 | #define PMIC_THERMAL_OPREGION_ID 0x8c |
| 23 | 24 | ||
| 24 | struct acpi_lpat { | ||
| 25 | int temp; | ||
| 26 | int raw; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct intel_pmic_opregion { | 25 | struct intel_pmic_opregion { |
| 30 | struct mutex lock; | 26 | struct mutex lock; |
| 31 | struct acpi_lpat *lpat; | 27 | struct acpi_lpat_conversion_table *lpat_table; |
| 32 | int lpat_count; | ||
| 33 | struct regmap *regmap; | 28 | struct regmap *regmap; |
| 34 | struct intel_pmic_opregion_data *data; | 29 | struct intel_pmic_opregion_data *data; |
| 35 | }; | 30 | }; |
| @@ -50,105 +45,6 @@ static int pmic_get_reg_bit(int address, struct pmic_table *table, | |||
| 50 | return -ENOENT; | 45 | return -ENOENT; |
| 51 | } | 46 | } |
| 52 | 47 | ||
| 53 | /** | ||
| 54 | * raw_to_temp(): Return temperature from raw value through LPAT table | ||
| 55 | * | ||
| 56 | * @lpat: the temperature_raw mapping table | ||
| 57 | * @count: the count of the above mapping table | ||
| 58 | * @raw: the raw value, used as a key to get the temerature from the | ||
| 59 | * above mapping table | ||
| 60 | * | ||
| 61 | * A positive value will be returned on success, a negative errno will | ||
| 62 | * be returned in error cases. | ||
| 63 | */ | ||
| 64 | static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw) | ||
| 65 | { | ||
| 66 | int i, delta_temp, delta_raw, temp; | ||
| 67 | |||
| 68 | for (i = 0; i < count - 1; i++) { | ||
| 69 | if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) || | ||
| 70 | (raw <= lpat[i].raw && raw >= lpat[i+1].raw)) | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | |||
| 74 | if (i == count - 1) | ||
| 75 | return -ENOENT; | ||
| 76 | |||
| 77 | delta_temp = lpat[i+1].temp - lpat[i].temp; | ||
| 78 | delta_raw = lpat[i+1].raw - lpat[i].raw; | ||
| 79 | temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw; | ||
| 80 | |||
| 81 | return temp; | ||
| 82 | } | ||
| 83 | |||
| 84 | /** | ||
| 85 | * temp_to_raw(): Return raw value from temperature through LPAT table | ||
| 86 | * | ||
| 87 | * @lpat: the temperature_raw mapping table | ||
| 88 | * @count: the count of the above mapping table | ||
| 89 | * @temp: the temperature, used as a key to get the raw value from the | ||
| 90 | * above mapping table | ||
| 91 | * | ||
| 92 | * A positive value will be returned on success, a negative errno will | ||
| 93 | * be returned in error cases. | ||
| 94 | */ | ||
| 95 | static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp) | ||
| 96 | { | ||
| 97 | int i, delta_temp, delta_raw, raw; | ||
| 98 | |||
| 99 | for (i = 0; i < count - 1; i++) { | ||
| 100 | if (temp >= lpat[i].temp && temp <= lpat[i+1].temp) | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (i == count - 1) | ||
| 105 | return -ENOENT; | ||
| 106 | |||
| 107 | delta_temp = lpat[i+1].temp - lpat[i].temp; | ||
| 108 | delta_raw = lpat[i+1].raw - lpat[i].raw; | ||
| 109 | raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp; | ||
| 110 | |||
| 111 | return raw; | ||
| 112 | } | ||
| 113 | |||
| 114 | static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion, | ||
| 115 | acpi_handle handle, struct device *dev) | ||
| 116 | { | ||
| 117 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 118 | union acpi_object *obj_p, *obj_e; | ||
| 119 | int *lpat, i; | ||
| 120 | acpi_status status; | ||
| 121 | |||
| 122 | status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer); | ||
| 123 | if (ACPI_FAILURE(status)) | ||
| 124 | return; | ||
| 125 | |||
| 126 | obj_p = (union acpi_object *)buffer.pointer; | ||
| 127 | if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) || | ||
| 128 | (obj_p->package.count % 2) || (obj_p->package.count < 4)) | ||
| 129 | goto out; | ||
| 130 | |||
| 131 | lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count, | ||
| 132 | GFP_KERNEL); | ||
| 133 | if (!lpat) | ||
| 134 | goto out; | ||
| 135 | |||
| 136 | for (i = 0; i < obj_p->package.count; i++) { | ||
| 137 | obj_e = &obj_p->package.elements[i]; | ||
| 138 | if (obj_e->type != ACPI_TYPE_INTEGER) { | ||
| 139 | devm_kfree(dev, lpat); | ||
| 140 | goto out; | ||
| 141 | } | ||
| 142 | lpat[i] = (s64)obj_e->integer.value; | ||
| 143 | } | ||
| 144 | |||
| 145 | opregion->lpat = (struct acpi_lpat *)lpat; | ||
| 146 | opregion->lpat_count = obj_p->package.count / 2; | ||
| 147 | |||
| 148 | out: | ||
| 149 | kfree(buffer.pointer); | ||
| 150 | } | ||
| 151 | |||
| 152 | static acpi_status intel_pmic_power_handler(u32 function, | 48 | static acpi_status intel_pmic_power_handler(u32 function, |
| 153 | acpi_physical_address address, u32 bits, u64 *value64, | 49 | acpi_physical_address address, u32 bits, u64 *value64, |
| 154 | void *handler_context, void *region_context) | 50 | void *handler_context, void *region_context) |
| @@ -192,12 +88,12 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion, | |||
| 192 | if (raw_temp < 0) | 88 | if (raw_temp < 0) |
| 193 | return raw_temp; | 89 | return raw_temp; |
| 194 | 90 | ||
| 195 | if (!opregion->lpat) { | 91 | if (!opregion->lpat_table) { |
| 196 | *value = raw_temp; | 92 | *value = raw_temp; |
| 197 | return 0; | 93 | return 0; |
| 198 | } | 94 | } |
| 199 | 95 | ||
| 200 | temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp); | 96 | temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp); |
| 201 | if (temp < 0) | 97 | if (temp < 0) |
| 202 | return temp; | 98 | return temp; |
| 203 | 99 | ||
| @@ -223,9 +119,8 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg, | |||
| 223 | if (!opregion->data->update_aux) | 119 | if (!opregion->data->update_aux) |
| 224 | return -ENXIO; | 120 | return -ENXIO; |
| 225 | 121 | ||
| 226 | if (opregion->lpat) { | 122 | if (opregion->lpat_table) { |
| 227 | raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count, | 123 | raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value); |
| 228 | *value); | ||
| 229 | if (raw_temp < 0) | 124 | if (raw_temp < 0) |
| 230 | return raw_temp; | 125 | return raw_temp; |
| 231 | } else { | 126 | } else { |
| @@ -314,6 +209,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, | |||
| 314 | { | 209 | { |
| 315 | acpi_status status; | 210 | acpi_status status; |
| 316 | struct intel_pmic_opregion *opregion; | 211 | struct intel_pmic_opregion *opregion; |
| 212 | int ret; | ||
| 317 | 213 | ||
| 318 | if (!dev || !regmap || !d) | 214 | if (!dev || !regmap || !d) |
| 319 | return -EINVAL; | 215 | return -EINVAL; |
| @@ -327,14 +223,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, | |||
| 327 | 223 | ||
| 328 | mutex_init(&opregion->lock); | 224 | mutex_init(&opregion->lock); |
| 329 | opregion->regmap = regmap; | 225 | opregion->regmap = regmap; |
| 330 | pmic_thermal_lpat(opregion, handle, dev); | 226 | opregion->lpat_table = acpi_lpat_get_conversion_table(handle); |
| 331 | 227 | ||
| 332 | status = acpi_install_address_space_handler(handle, | 228 | status = acpi_install_address_space_handler(handle, |
| 333 | PMIC_POWER_OPREGION_ID, | 229 | PMIC_POWER_OPREGION_ID, |
| 334 | intel_pmic_power_handler, | 230 | intel_pmic_power_handler, |
| 335 | NULL, opregion); | 231 | NULL, opregion); |
| 336 | if (ACPI_FAILURE(status)) | 232 | if (ACPI_FAILURE(status)) { |
| 337 | return -ENODEV; | 233 | ret = -ENODEV; |
| 234 | goto out_error; | ||
| 235 | } | ||
| 338 | 236 | ||
| 339 | status = acpi_install_address_space_handler(handle, | 237 | status = acpi_install_address_space_handler(handle, |
| 340 | PMIC_THERMAL_OPREGION_ID, | 238 | PMIC_THERMAL_OPREGION_ID, |
| @@ -343,11 +241,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, | |||
| 343 | if (ACPI_FAILURE(status)) { | 241 | if (ACPI_FAILURE(status)) { |
| 344 | acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, | 242 | acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, |
| 345 | intel_pmic_power_handler); | 243 | intel_pmic_power_handler); |
| 346 | return -ENODEV; | 244 | ret = -ENODEV; |
| 245 | goto out_error; | ||
| 347 | } | 246 | } |
| 348 | 247 | ||
| 349 | opregion->data = d; | 248 | opregion->data = d; |
| 350 | return 0; | 249 | return 0; |
| 250 | |||
| 251 | out_error: | ||
| 252 | acpi_lpat_free_conversion_table(opregion->lpat_table); | ||
| 253 | return ret; | ||
| 351 | } | 254 | } |
| 352 | EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); | 255 | EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); |
| 353 | 256 | ||
diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile index d4413698a85f..ba77a34f659f 100644 --- a/drivers/thermal/int340x_thermal/Makefile +++ b/drivers/thermal/int340x_thermal/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o | 1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o |
| 2 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o | ||
| 2 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o | 3 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o |
| 3 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o | 4 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o |
| 4 | obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o | 5 | obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o |
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c index 65a98a97df07..25d244cbbe8f 100644 --- a/drivers/thermal/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c | |||
| @@ -18,19 +18,15 @@ | |||
| 18 | 18 | ||
| 19 | enum int3400_thermal_uuid { | 19 | enum int3400_thermal_uuid { |
| 20 | INT3400_THERMAL_PASSIVE_1, | 20 | INT3400_THERMAL_PASSIVE_1, |
| 21 | INT3400_THERMAL_PASSIVE_2, | ||
| 22 | INT3400_THERMAL_ACTIVE, | 21 | INT3400_THERMAL_ACTIVE, |
| 23 | INT3400_THERMAL_CRITICAL, | 22 | INT3400_THERMAL_CRITICAL, |
| 24 | INT3400_THERMAL_COOLING_MODE, | ||
| 25 | INT3400_THERMAL_MAXIMUM_UUID, | 23 | INT3400_THERMAL_MAXIMUM_UUID, |
| 26 | }; | 24 | }; |
| 27 | 25 | ||
| 28 | static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { | 26 | static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { |
| 29 | "42A441D6-AE6A-462b-A84B-4A8CE79027D3", | 27 | "42A441D6-AE6A-462b-A84B-4A8CE79027D3", |
| 30 | "9E04115A-AE87-4D1C-9500-0F3E340BFE75", | ||
| 31 | "3A95C389-E4B8-4629-A526-C52C88626BAE", | 28 | "3A95C389-E4B8-4629-A526-C52C88626BAE", |
| 32 | "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", | 29 | "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", |
| 33 | "16CAF1B7-DD38-40ed-B1C1-1B8A1913D531", | ||
| 34 | }; | 30 | }; |
| 35 | 31 | ||
| 36 | struct int3400_thermal_priv { | 32 | struct int3400_thermal_priv { |
diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c index c5cbc3af3a05..69df3d960303 100644 --- a/drivers/thermal/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c | |||
| @@ -14,152 +14,39 @@ | |||
| 14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
| 15 | #include <linux/acpi.h> | 15 | #include <linux/acpi.h> |
| 16 | #include <linux/thermal.h> | 16 | #include <linux/thermal.h> |
| 17 | #include "int340x_thermal_zone.h" | ||
| 17 | 18 | ||
| 18 | #define ACPI_ACTIVE_COOLING_MAX_NR 10 | 19 | #define INT3402_PERF_CHANGED_EVENT 0x80 |
| 19 | 20 | #define INT3402_THERMAL_EVENT 0x90 | |
| 20 | struct active_trip { | ||
| 21 | unsigned long temp; | ||
| 22 | int id; | ||
| 23 | bool valid; | ||
| 24 | }; | ||
| 25 | 21 | ||
| 26 | struct int3402_thermal_data { | 22 | struct int3402_thermal_data { |
| 27 | unsigned long *aux_trips; | ||
| 28 | int aux_trip_nr; | ||
| 29 | unsigned long psv_temp; | ||
| 30 | int psv_trip_id; | ||
| 31 | unsigned long crt_temp; | ||
| 32 | int crt_trip_id; | ||
| 33 | unsigned long hot_temp; | ||
| 34 | int hot_trip_id; | ||
| 35 | struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR]; | ||
| 36 | acpi_handle *handle; | 23 | acpi_handle *handle; |
| 24 | struct int34x_thermal_zone *int340x_zone; | ||
| 37 | }; | 25 | }; |
| 38 | 26 | ||
| 39 | static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, | 27 | static void int3402_notify(acpi_handle handle, u32 event, void *data) |
| 40 | unsigned long *temp) | ||
| 41 | { | ||
| 42 | struct int3402_thermal_data *d = zone->devdata; | ||
| 43 | unsigned long long tmp; | ||
| 44 | acpi_status status; | ||
| 45 | |||
| 46 | status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp); | ||
| 47 | if (ACPI_FAILURE(status)) | ||
| 48 | return -ENODEV; | ||
| 49 | |||
| 50 | /* _TMP returns the temperature in tenths of degrees Kelvin */ | ||
| 51 | *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); | ||
| 52 | |||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone, | ||
| 57 | int trip, unsigned long *temp) | ||
| 58 | { | 28 | { |
| 59 | struct int3402_thermal_data *d = zone->devdata; | 29 | struct int3402_thermal_data *priv = data; |
| 60 | int i; | 30 | |
| 61 | 31 | if (!priv) | |
| 62 | if (trip < d->aux_trip_nr) | 32 | return; |
| 63 | *temp = d->aux_trips[trip]; | 33 | |
| 64 | else if (trip == d->crt_trip_id) | 34 | switch (event) { |
| 65 | *temp = d->crt_temp; | 35 | case INT3402_PERF_CHANGED_EVENT: |
| 66 | else if (trip == d->psv_trip_id) | 36 | break; |
| 67 | *temp = d->psv_temp; | 37 | case INT3402_THERMAL_EVENT: |
| 68 | else if (trip == d->hot_trip_id) | 38 | int340x_thermal_zone_device_update(priv->int340x_zone); |
| 69 | *temp = d->hot_temp; | 39 | break; |
| 70 | else { | 40 | default: |
| 71 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | 41 | break; |
| 72 | if (d->act_trips[i].valid && | ||
| 73 | d->act_trips[i].id == trip) { | ||
| 74 | *temp = d->act_trips[i].temp; | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | if (i == ACPI_ACTIVE_COOLING_MAX_NR) | ||
| 79 | return -EINVAL; | ||
| 80 | } | 42 | } |
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone, | ||
| 85 | int trip, enum thermal_trip_type *type) | ||
| 86 | { | ||
| 87 | struct int3402_thermal_data *d = zone->devdata; | ||
| 88 | int i; | ||
| 89 | |||
| 90 | if (trip < d->aux_trip_nr) | ||
| 91 | *type = THERMAL_TRIP_PASSIVE; | ||
| 92 | else if (trip == d->crt_trip_id) | ||
| 93 | *type = THERMAL_TRIP_CRITICAL; | ||
| 94 | else if (trip == d->hot_trip_id) | ||
| 95 | *type = THERMAL_TRIP_HOT; | ||
| 96 | else if (trip == d->psv_trip_id) | ||
| 97 | *type = THERMAL_TRIP_PASSIVE; | ||
| 98 | else { | ||
| 99 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | ||
| 100 | if (d->act_trips[i].valid && | ||
| 101 | d->act_trips[i].id == trip) { | ||
| 102 | *type = THERMAL_TRIP_ACTIVE; | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | if (i == ACPI_ACTIVE_COOLING_MAX_NR) | ||
| 107 | return -EINVAL; | ||
| 108 | } | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip, | ||
| 113 | unsigned long temp) | ||
| 114 | { | ||
| 115 | struct int3402_thermal_data *d = zone->devdata; | ||
| 116 | acpi_status status; | ||
| 117 | char name[10]; | ||
| 118 | |||
| 119 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
| 120 | status = acpi_execute_simple_method(d->handle, name, | ||
| 121 | MILLICELSIUS_TO_DECI_KELVIN(temp)); | ||
| 122 | if (ACPI_FAILURE(status)) | ||
| 123 | return -EIO; | ||
| 124 | |||
| 125 | d->aux_trips[trip] = temp; | ||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static struct thermal_zone_device_ops int3402_thermal_zone_ops = { | ||
| 130 | .get_temp = int3402_thermal_get_zone_temp, | ||
| 131 | .get_trip_temp = int3402_thermal_get_trip_temp, | ||
| 132 | .get_trip_type = int3402_thermal_get_trip_type, | ||
| 133 | .set_trip_temp = int3402_thermal_set_trip_temp, | ||
| 134 | }; | ||
| 135 | |||
| 136 | static struct thermal_zone_params int3402_thermal_params = { | ||
| 137 | .governor_name = "user_space", | ||
| 138 | .no_hwmon = true, | ||
| 139 | }; | ||
| 140 | |||
| 141 | static int int3402_thermal_get_temp(acpi_handle handle, char *name, | ||
| 142 | unsigned long *temp) | ||
| 143 | { | ||
| 144 | unsigned long long r; | ||
| 145 | acpi_status status; | ||
| 146 | |||
| 147 | status = acpi_evaluate_integer(handle, name, NULL, &r); | ||
| 148 | if (ACPI_FAILURE(status)) | ||
| 149 | return -EIO; | ||
| 150 | |||
| 151 | *temp = DECI_KELVIN_TO_MILLICELSIUS(r); | ||
| 152 | return 0; | ||
| 153 | } | 43 | } |
| 154 | 44 | ||
| 155 | static int int3402_thermal_probe(struct platform_device *pdev) | 45 | static int int3402_thermal_probe(struct platform_device *pdev) |
| 156 | { | 46 | { |
| 157 | struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); | 47 | struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); |
| 158 | struct int3402_thermal_data *d; | 48 | struct int3402_thermal_data *d; |
| 159 | struct thermal_zone_device *zone; | 49 | int ret; |
| 160 | acpi_status status; | ||
| 161 | unsigned long long trip_cnt; | ||
| 162 | int trip_mask = 0, i; | ||
| 163 | 50 | ||
| 164 | if (!acpi_has_method(adev->handle, "_TMP")) | 51 | if (!acpi_has_method(adev->handle, "_TMP")) |
| 165 | return -ENODEV; | 52 | return -ENODEV; |
| @@ -168,54 +55,33 @@ static int int3402_thermal_probe(struct platform_device *pdev) | |||
| 168 | if (!d) | 55 | if (!d) |
| 169 | return -ENOMEM; | 56 | return -ENOMEM; |
| 170 | 57 | ||
| 171 | status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); | 58 | d->int340x_zone = int340x_thermal_zone_add(adev, NULL); |
| 172 | if (ACPI_FAILURE(status)) | 59 | if (IS_ERR(d->int340x_zone)) |
| 173 | trip_cnt = 0; | 60 | return PTR_ERR(d->int340x_zone); |
| 174 | else { | 61 | |
| 175 | d->aux_trips = devm_kzalloc(&pdev->dev, | 62 | ret = acpi_install_notify_handler(adev->handle, |
| 176 | sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL); | 63 | ACPI_DEVICE_NOTIFY, |
| 177 | if (!d->aux_trips) | 64 | int3402_notify, |
| 178 | return -ENOMEM; | 65 | d); |
| 179 | trip_mask = trip_cnt - 1; | 66 | if (ret) { |
| 180 | d->handle = adev->handle; | 67 | int340x_thermal_zone_remove(d->int340x_zone); |
| 181 | d->aux_trip_nr = trip_cnt; | 68 | return ret; |
| 182 | } | ||
| 183 | |||
| 184 | d->crt_trip_id = -1; | ||
| 185 | if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp)) | ||
| 186 | d->crt_trip_id = trip_cnt++; | ||
| 187 | d->hot_trip_id = -1; | ||
| 188 | if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp)) | ||
| 189 | d->hot_trip_id = trip_cnt++; | ||
| 190 | d->psv_trip_id = -1; | ||
| 191 | if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp)) | ||
| 192 | d->psv_trip_id = trip_cnt++; | ||
| 193 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | ||
| 194 | char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; | ||
| 195 | if (int3402_thermal_get_temp(adev->handle, name, | ||
| 196 | &d->act_trips[i].temp)) | ||
| 197 | break; | ||
| 198 | d->act_trips[i].id = trip_cnt++; | ||
| 199 | d->act_trips[i].valid = true; | ||
| 200 | } | 69 | } |
| 201 | 70 | ||
| 202 | zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt, | 71 | d->handle = adev->handle; |
| 203 | trip_mask, d, | 72 | platform_set_drvdata(pdev, d); |
| 204 | &int3402_thermal_zone_ops, | ||
| 205 | &int3402_thermal_params, | ||
| 206 | 0, 0); | ||
| 207 | if (IS_ERR(zone)) | ||
| 208 | return PTR_ERR(zone); | ||
| 209 | platform_set_drvdata(pdev, zone); | ||
| 210 | 73 | ||
| 211 | return 0; | 74 | return 0; |
| 212 | } | 75 | } |
| 213 | 76 | ||
| 214 | static int int3402_thermal_remove(struct platform_device *pdev) | 77 | static int int3402_thermal_remove(struct platform_device *pdev) |
| 215 | { | 78 | { |
| 216 | struct thermal_zone_device *zone = platform_get_drvdata(pdev); | 79 | struct int3402_thermal_data *d = platform_get_drvdata(pdev); |
| 80 | |||
| 81 | acpi_remove_notify_handler(d->handle, | ||
| 82 | ACPI_DEVICE_NOTIFY, int3402_notify); | ||
| 83 | int340x_thermal_zone_remove(d->int340x_zone); | ||
| 217 | 84 | ||
| 218 | thermal_zone_device_unregister(zone); | ||
| 219 | return 0; | 85 | return 0; |
| 220 | } | 86 | } |
| 221 | 87 | ||
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c index 0faf500d8a77..50a7a08e3a15 100644 --- a/drivers/thermal/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
| 20 | #include <linux/thermal.h> | 20 | #include <linux/thermal.h> |
| 21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
| 22 | #include "int340x_thermal_zone.h" | ||
| 22 | 23 | ||
| 23 | #define INT3403_TYPE_SENSOR 0x03 | 24 | #define INT3403_TYPE_SENSOR 0x03 |
| 24 | #define INT3403_TYPE_CHARGER 0x0B | 25 | #define INT3403_TYPE_CHARGER 0x0B |
| @@ -26,18 +27,9 @@ | |||
| 26 | #define INT3403_PERF_CHANGED_EVENT 0x80 | 27 | #define INT3403_PERF_CHANGED_EVENT 0x80 |
| 27 | #define INT3403_THERMAL_EVENT 0x90 | 28 | #define INT3403_THERMAL_EVENT 0x90 |
| 28 | 29 | ||
| 29 | #define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) | 30 | /* Preserved structure for future expandbility */ |
| 30 | #define KELVIN_OFFSET 2732 | ||
| 31 | #define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off)) | ||
| 32 | |||
| 33 | struct int3403_sensor { | 31 | struct int3403_sensor { |
| 34 | struct thermal_zone_device *tzone; | 32 | struct int34x_thermal_zone *int340x_zone; |
| 35 | unsigned long *thresholds; | ||
| 36 | unsigned long crit_temp; | ||
| 37 | int crit_trip_id; | ||
| 38 | unsigned long psv_temp; | ||
| 39 | int psv_trip_id; | ||
| 40 | |||
| 41 | }; | 33 | }; |
| 42 | 34 | ||
| 43 | struct int3403_performance_state { | 35 | struct int3403_performance_state { |
| @@ -63,126 +55,6 @@ struct int3403_priv { | |||
| 63 | void *priv; | 55 | void *priv; |
| 64 | }; | 56 | }; |
| 65 | 57 | ||
| 66 | static int sys_get_curr_temp(struct thermal_zone_device *tzone, | ||
| 67 | unsigned long *temp) | ||
| 68 | { | ||
| 69 | struct int3403_priv *priv = tzone->devdata; | ||
| 70 | struct acpi_device *device = priv->adev; | ||
| 71 | unsigned long long tmp; | ||
| 72 | acpi_status status; | ||
| 73 | |||
| 74 | status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp); | ||
| 75 | if (ACPI_FAILURE(status)) | ||
| 76 | return -EIO; | ||
| 77 | |||
| 78 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET); | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int sys_get_trip_hyst(struct thermal_zone_device *tzone, | ||
| 84 | int trip, unsigned long *temp) | ||
| 85 | { | ||
| 86 | struct int3403_priv *priv = tzone->devdata; | ||
| 87 | struct acpi_device *device = priv->adev; | ||
| 88 | unsigned long long hyst; | ||
| 89 | acpi_status status; | ||
| 90 | |||
| 91 | status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst); | ||
| 92 | if (ACPI_FAILURE(status)) | ||
| 93 | return -EIO; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Thermal hysteresis represents a temperature difference. | ||
| 97 | * Kelvin and Celsius have same degree size. So the | ||
| 98 | * conversion here between tenths of degree Kelvin unit | ||
| 99 | * and Milli-Celsius unit is just to multiply 100. | ||
| 100 | */ | ||
| 101 | *temp = hyst * 100; | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | static int sys_get_trip_temp(struct thermal_zone_device *tzone, | ||
| 107 | int trip, unsigned long *temp) | ||
| 108 | { | ||
| 109 | struct int3403_priv *priv = tzone->devdata; | ||
| 110 | struct int3403_sensor *obj = priv->priv; | ||
| 111 | |||
| 112 | if (priv->type != INT3403_TYPE_SENSOR || !obj) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | if (trip == obj->crit_trip_id) | ||
| 116 | *temp = obj->crit_temp; | ||
| 117 | else if (trip == obj->psv_trip_id) | ||
| 118 | *temp = obj->psv_temp; | ||
| 119 | else { | ||
| 120 | /* | ||
| 121 | * get_trip_temp is a mandatory callback but | ||
| 122 | * PATx method doesn't return any value, so return | ||
| 123 | * cached value, which was last set from user space | ||
| 124 | */ | ||
| 125 | *temp = obj->thresholds[trip]; | ||
| 126 | } | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int sys_get_trip_type(struct thermal_zone_device *thermal, | ||
| 132 | int trip, enum thermal_trip_type *type) | ||
| 133 | { | ||
| 134 | struct int3403_priv *priv = thermal->devdata; | ||
| 135 | struct int3403_sensor *obj = priv->priv; | ||
| 136 | |||
| 137 | /* Mandatory callback, may not mean much here */ | ||
| 138 | if (trip == obj->crit_trip_id) | ||
| 139 | *type = THERMAL_TRIP_CRITICAL; | ||
| 140 | else | ||
| 141 | *type = THERMAL_TRIP_PASSIVE; | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip, | ||
| 147 | unsigned long temp) | ||
| 148 | { | ||
| 149 | struct int3403_priv *priv = tzone->devdata; | ||
| 150 | struct acpi_device *device = priv->adev; | ||
| 151 | struct int3403_sensor *obj = priv->priv; | ||
| 152 | acpi_status status; | ||
| 153 | char name[10]; | ||
| 154 | int ret = 0; | ||
| 155 | |||
| 156 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
| 157 | if (acpi_has_method(device->handle, name)) { | ||
| 158 | status = acpi_execute_simple_method(device->handle, name, | ||
| 159 | MILLI_CELSIUS_TO_DECI_KELVIN(temp, | ||
| 160 | KELVIN_OFFSET)); | ||
| 161 | if (ACPI_FAILURE(status)) | ||
| 162 | ret = -EIO; | ||
| 163 | else | ||
| 164 | obj->thresholds[trip] = temp; | ||
| 165 | } else { | ||
| 166 | ret = -EIO; | ||
| 167 | dev_err(&device->dev, "sys_set_trip_temp: method not found\n"); | ||
| 168 | } | ||
| 169 | |||
| 170 | return ret; | ||
| 171 | } | ||
| 172 | |||
| 173 | static struct thermal_zone_device_ops tzone_ops = { | ||
| 174 | .get_temp = sys_get_curr_temp, | ||
| 175 | .get_trip_temp = sys_get_trip_temp, | ||
| 176 | .get_trip_type = sys_get_trip_type, | ||
| 177 | .set_trip_temp = sys_set_trip_temp, | ||
| 178 | .get_trip_hyst = sys_get_trip_hyst, | ||
| 179 | }; | ||
| 180 | |||
| 181 | static struct thermal_zone_params int3403_thermal_params = { | ||
| 182 | .governor_name = "user_space", | ||
| 183 | .no_hwmon = true, | ||
| 184 | }; | ||
| 185 | |||
| 186 | static void int3403_notify(acpi_handle handle, | 58 | static void int3403_notify(acpi_handle handle, |
| 187 | u32 event, void *data) | 59 | u32 event, void *data) |
| 188 | { | 60 | { |
| @@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle, | |||
| 200 | case INT3403_PERF_CHANGED_EVENT: | 72 | case INT3403_PERF_CHANGED_EVENT: |
| 201 | break; | 73 | break; |
| 202 | case INT3403_THERMAL_EVENT: | 74 | case INT3403_THERMAL_EVENT: |
| 203 | thermal_zone_device_update(obj->tzone); | 75 | int340x_thermal_zone_device_update(obj->int340x_zone); |
| 204 | break; | 76 | break; |
| 205 | default: | 77 | default: |
| 206 | dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); | 78 | dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); |
| @@ -208,41 +80,10 @@ static void int3403_notify(acpi_handle handle, | |||
| 208 | } | 80 | } |
| 209 | } | 81 | } |
| 210 | 82 | ||
| 211 | static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp) | ||
| 212 | { | ||
| 213 | unsigned long long crt; | ||
| 214 | acpi_status status; | ||
| 215 | |||
| 216 | status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt); | ||
| 217 | if (ACPI_FAILURE(status)) | ||
| 218 | return -EIO; | ||
| 219 | |||
| 220 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET); | ||
| 221 | |||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp) | ||
| 226 | { | ||
| 227 | unsigned long long psv; | ||
| 228 | acpi_status status; | ||
| 229 | |||
| 230 | status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv); | ||
| 231 | if (ACPI_FAILURE(status)) | ||
| 232 | return -EIO; | ||
| 233 | |||
| 234 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET); | ||
| 235 | |||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | static int int3403_sensor_add(struct int3403_priv *priv) | 83 | static int int3403_sensor_add(struct int3403_priv *priv) |
| 240 | { | 84 | { |
| 241 | int result = 0; | 85 | int result = 0; |
| 242 | acpi_status status; | ||
| 243 | struct int3403_sensor *obj; | 86 | struct int3403_sensor *obj; |
| 244 | unsigned long long trip_cnt; | ||
| 245 | int trip_mask = 0; | ||
| 246 | 87 | ||
| 247 | obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); | 88 | obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); |
| 248 | if (!obj) | 89 | if (!obj) |
| @@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv) | |||
| 250 | 91 | ||
| 251 | priv->priv = obj; | 92 | priv->priv = obj; |
| 252 | 93 | ||
| 253 | status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL, | 94 | obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL); |
| 254 | &trip_cnt); | 95 | if (IS_ERR(obj->int340x_zone)) |
| 255 | if (ACPI_FAILURE(status)) | 96 | return PTR_ERR(obj->int340x_zone); |
| 256 | trip_cnt = 0; | ||
| 257 | |||
| 258 | if (trip_cnt) { | ||
| 259 | /* We have to cache, thresholds can't be readback */ | ||
| 260 | obj->thresholds = devm_kzalloc(&priv->pdev->dev, | ||
| 261 | sizeof(*obj->thresholds) * trip_cnt, | ||
| 262 | GFP_KERNEL); | ||
| 263 | if (!obj->thresholds) { | ||
| 264 | result = -ENOMEM; | ||
| 265 | goto err_free_obj; | ||
| 266 | } | ||
| 267 | trip_mask = BIT(trip_cnt) - 1; | ||
| 268 | } | ||
| 269 | |||
| 270 | obj->psv_trip_id = -1; | ||
| 271 | if (!sys_get_trip_psv(priv->adev, &obj->psv_temp)) | ||
| 272 | obj->psv_trip_id = trip_cnt++; | ||
| 273 | |||
| 274 | obj->crit_trip_id = -1; | ||
| 275 | if (!sys_get_trip_crt(priv->adev, &obj->crit_temp)) | ||
| 276 | obj->crit_trip_id = trip_cnt++; | ||
| 277 | |||
| 278 | obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev), | ||
| 279 | trip_cnt, trip_mask, priv, &tzone_ops, | ||
| 280 | &int3403_thermal_params, 0, 0); | ||
| 281 | if (IS_ERR(obj->tzone)) { | ||
| 282 | result = PTR_ERR(obj->tzone); | ||
| 283 | obj->tzone = NULL; | ||
| 284 | goto err_free_obj; | ||
| 285 | } | ||
| 286 | 97 | ||
| 287 | result = acpi_install_notify_handler(priv->adev->handle, | 98 | result = acpi_install_notify_handler(priv->adev->handle, |
| 288 | ACPI_DEVICE_NOTIFY, int3403_notify, | 99 | ACPI_DEVICE_NOTIFY, int3403_notify, |
| @@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv) | |||
| 293 | return 0; | 104 | return 0; |
| 294 | 105 | ||
| 295 | err_free_obj: | 106 | err_free_obj: |
| 296 | thermal_zone_device_unregister(obj->tzone); | 107 | int340x_thermal_zone_remove(obj->int340x_zone); |
| 297 | return result; | 108 | return result; |
| 298 | } | 109 | } |
| 299 | 110 | ||
| @@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv) | |||
| 303 | 114 | ||
| 304 | acpi_remove_notify_handler(priv->adev->handle, | 115 | acpi_remove_notify_handler(priv->adev->handle, |
| 305 | ACPI_DEVICE_NOTIFY, int3403_notify); | 116 | ACPI_DEVICE_NOTIFY, int3403_notify); |
| 306 | thermal_zone_device_unregister(obj->tzone); | 117 | int340x_thermal_zone_remove(obj->int340x_zone); |
| 118 | |||
| 307 | return 0; | 119 | return 0; |
| 308 | } | 120 | } |
| 309 | 121 | ||
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c new file mode 100644 index 000000000000..f88b08877025 --- /dev/null +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c | |||
| @@ -0,0 +1,276 @@ | |||
| 1 | /* | ||
| 2 | * int340x_thermal_zone.c | ||
| 3 | * Copyright (c) 2015, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/acpi.h> | ||
| 19 | #include <linux/thermal.h> | ||
| 20 | #include "int340x_thermal_zone.h" | ||
| 21 | |||
| 22 | static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, | ||
| 23 | unsigned long *temp) | ||
| 24 | { | ||
| 25 | struct int34x_thermal_zone *d = zone->devdata; | ||
| 26 | unsigned long long tmp; | ||
| 27 | acpi_status status; | ||
| 28 | |||
| 29 | if (d->override_ops && d->override_ops->get_temp) | ||
| 30 | return d->override_ops->get_temp(zone, temp); | ||
| 31 | |||
| 32 | status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp); | ||
| 33 | if (ACPI_FAILURE(status)) | ||
| 34 | return -EIO; | ||
| 35 | |||
| 36 | if (d->lpat_table) { | ||
| 37 | int conv_temp; | ||
| 38 | |||
| 39 | conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp); | ||
| 40 | if (conv_temp < 0) | ||
| 41 | return conv_temp; | ||
| 42 | |||
| 43 | *temp = (unsigned long)conv_temp * 10; | ||
| 44 | } else | ||
| 45 | /* _TMP returns the temperature in tenths of degrees Kelvin */ | ||
| 46 | *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); | ||
| 47 | |||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, | ||
| 52 | int trip, unsigned long *temp) | ||
| 53 | { | ||
| 54 | struct int34x_thermal_zone *d = zone->devdata; | ||
| 55 | int i; | ||
| 56 | |||
| 57 | if (d->override_ops && d->override_ops->get_trip_temp) | ||
| 58 | return d->override_ops->get_trip_temp(zone, trip, temp); | ||
| 59 | |||
| 60 | if (trip < d->aux_trip_nr) | ||
| 61 | *temp = d->aux_trips[trip]; | ||
| 62 | else if (trip == d->crt_trip_id) | ||
| 63 | *temp = d->crt_temp; | ||
| 64 | else if (trip == d->psv_trip_id) | ||
| 65 | *temp = d->psv_temp; | ||
| 66 | else if (trip == d->hot_trip_id) | ||
| 67 | *temp = d->hot_temp; | ||
| 68 | else { | ||
| 69 | for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { | ||
| 70 | if (d->act_trips[i].valid && | ||
| 71 | d->act_trips[i].id == trip) { | ||
| 72 | *temp = d->act_trips[i].temp; | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) | ||
| 77 | return -EINVAL; | ||
| 78 | } | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, | ||
| 84 | int trip, | ||
| 85 | enum thermal_trip_type *type) | ||
| 86 | { | ||
| 87 | struct int34x_thermal_zone *d = zone->devdata; | ||
| 88 | int i; | ||
| 89 | |||
| 90 | if (d->override_ops && d->override_ops->get_trip_type) | ||
| 91 | return d->override_ops->get_trip_type(zone, trip, type); | ||
| 92 | |||
| 93 | if (trip < d->aux_trip_nr) | ||
| 94 | *type = THERMAL_TRIP_PASSIVE; | ||
| 95 | else if (trip == d->crt_trip_id) | ||
| 96 | *type = THERMAL_TRIP_CRITICAL; | ||
| 97 | else if (trip == d->hot_trip_id) | ||
| 98 | *type = THERMAL_TRIP_HOT; | ||
| 99 | else if (trip == d->psv_trip_id) | ||
| 100 | *type = THERMAL_TRIP_PASSIVE; | ||
| 101 | else { | ||
| 102 | for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { | ||
| 103 | if (d->act_trips[i].valid && | ||
| 104 | d->act_trips[i].id == trip) { | ||
| 105 | *type = THERMAL_TRIP_ACTIVE; | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) | ||
| 110 | return -EINVAL; | ||
| 111 | } | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, | ||
| 117 | int trip, unsigned long temp) | ||
| 118 | { | ||
| 119 | struct int34x_thermal_zone *d = zone->devdata; | ||
| 120 | acpi_status status; | ||
| 121 | char name[10]; | ||
| 122 | |||
| 123 | if (d->override_ops && d->override_ops->set_trip_temp) | ||
| 124 | return d->override_ops->set_trip_temp(zone, trip, temp); | ||
| 125 | |||
| 126 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
| 127 | status = acpi_execute_simple_method(d->adev->handle, name, | ||
| 128 | MILLICELSIUS_TO_DECI_KELVIN(temp)); | ||
| 129 | if (ACPI_FAILURE(status)) | ||
| 130 | return -EIO; | ||
| 131 | |||
| 132 | d->aux_trips[trip] = temp; | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | |||
| 138 | static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, | ||
| 139 | int trip, unsigned long *temp) | ||
| 140 | { | ||
| 141 | struct int34x_thermal_zone *d = zone->devdata; | ||
| 142 | acpi_status status; | ||
| 143 | unsigned long long hyst; | ||
| 144 | |||
| 145 | if (d->override_ops && d->override_ops->get_trip_hyst) | ||
| 146 | return d->override_ops->get_trip_hyst(zone, trip, temp); | ||
| 147 | |||
| 148 | status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst); | ||
| 149 | if (ACPI_FAILURE(status)) | ||
| 150 | return -EIO; | ||
| 151 | |||
| 152 | *temp = hyst * 100; | ||
| 153 | |||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static struct thermal_zone_device_ops int340x_thermal_zone_ops = { | ||
| 158 | .get_temp = int340x_thermal_get_zone_temp, | ||
| 159 | .get_trip_temp = int340x_thermal_get_trip_temp, | ||
| 160 | .get_trip_type = int340x_thermal_get_trip_type, | ||
| 161 | .set_trip_temp = int340x_thermal_set_trip_temp, | ||
| 162 | .get_trip_hyst = int340x_thermal_get_trip_hyst, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, | ||
| 166 | unsigned long *temp) | ||
| 167 | { | ||
| 168 | unsigned long long r; | ||
| 169 | acpi_status status; | ||
| 170 | |||
| 171 | status = acpi_evaluate_integer(handle, name, NULL, &r); | ||
| 172 | if (ACPI_FAILURE(status)) | ||
| 173 | return -EIO; | ||
| 174 | |||
| 175 | *temp = DECI_KELVIN_TO_MILLICELSIUS(r); | ||
| 176 | |||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | static struct thermal_zone_params int340x_thermal_params = { | ||
| 181 | .governor_name = "user_space", | ||
| 182 | .no_hwmon = true, | ||
| 183 | }; | ||
| 184 | |||
| 185 | struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, | ||
| 186 | struct thermal_zone_device_ops *override_ops) | ||
| 187 | { | ||
| 188 | struct int34x_thermal_zone *int34x_thermal_zone; | ||
| 189 | acpi_status status; | ||
| 190 | unsigned long long trip_cnt; | ||
| 191 | int trip_mask = 0, i; | ||
| 192 | int ret; | ||
| 193 | |||
| 194 | int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone), | ||
| 195 | GFP_KERNEL); | ||
| 196 | if (!int34x_thermal_zone) | ||
| 197 | return ERR_PTR(-ENOMEM); | ||
| 198 | |||
| 199 | int34x_thermal_zone->adev = adev; | ||
| 200 | int34x_thermal_zone->override_ops = override_ops; | ||
| 201 | |||
| 202 | status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); | ||
| 203 | if (ACPI_FAILURE(status)) | ||
| 204 | trip_cnt = 0; | ||
| 205 | else { | ||
| 206 | int34x_thermal_zone->aux_trips = kzalloc( | ||
| 207 | sizeof(*int34x_thermal_zone->aux_trips) * | ||
| 208 | trip_cnt, GFP_KERNEL); | ||
| 209 | if (!int34x_thermal_zone->aux_trips) { | ||
| 210 | ret = -ENOMEM; | ||
| 211 | goto free_mem; | ||
| 212 | } | ||
| 213 | trip_mask = BIT(trip_cnt) - 1; | ||
| 214 | int34x_thermal_zone->aux_trip_nr = trip_cnt; | ||
| 215 | } | ||
| 216 | |||
| 217 | int34x_thermal_zone->crt_trip_id = -1; | ||
| 218 | if (!int340x_thermal_get_trip_config(adev->handle, "_CRT", | ||
| 219 | &int34x_thermal_zone->crt_temp)) | ||
| 220 | int34x_thermal_zone->crt_trip_id = trip_cnt++; | ||
| 221 | int34x_thermal_zone->hot_trip_id = -1; | ||
| 222 | if (!int340x_thermal_get_trip_config(adev->handle, "_HOT", | ||
| 223 | &int34x_thermal_zone->hot_temp)) | ||
| 224 | int34x_thermal_zone->hot_trip_id = trip_cnt++; | ||
| 225 | int34x_thermal_zone->psv_trip_id = -1; | ||
| 226 | if (!int340x_thermal_get_trip_config(adev->handle, "_PSV", | ||
| 227 | &int34x_thermal_zone->psv_temp)) | ||
| 228 | int34x_thermal_zone->psv_trip_id = trip_cnt++; | ||
| 229 | for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { | ||
| 230 | char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; | ||
| 231 | |||
| 232 | if (int340x_thermal_get_trip_config(adev->handle, name, | ||
| 233 | &int34x_thermal_zone->act_trips[i].temp)) | ||
| 234 | break; | ||
| 235 | |||
| 236 | int34x_thermal_zone->act_trips[i].id = trip_cnt++; | ||
| 237 | int34x_thermal_zone->act_trips[i].valid = true; | ||
| 238 | } | ||
| 239 | int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table( | ||
| 240 | adev->handle); | ||
| 241 | |||
| 242 | int34x_thermal_zone->zone = thermal_zone_device_register( | ||
| 243 | acpi_device_bid(adev), | ||
| 244 | trip_cnt, | ||
| 245 | trip_mask, int34x_thermal_zone, | ||
| 246 | &int340x_thermal_zone_ops, | ||
| 247 | &int340x_thermal_params, | ||
| 248 | 0, 0); | ||
| 249 | if (IS_ERR(int34x_thermal_zone->zone)) { | ||
| 250 | ret = PTR_ERR(int34x_thermal_zone->zone); | ||
| 251 | goto free_lpat; | ||
| 252 | } | ||
| 253 | |||
| 254 | return int34x_thermal_zone; | ||
| 255 | |||
| 256 | free_lpat: | ||
| 257 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); | ||
| 258 | free_mem: | ||
| 259 | kfree(int34x_thermal_zone); | ||
| 260 | return ERR_PTR(ret); | ||
| 261 | } | ||
| 262 | EXPORT_SYMBOL_GPL(int340x_thermal_zone_add); | ||
| 263 | |||
| 264 | void int340x_thermal_zone_remove(struct int34x_thermal_zone | ||
| 265 | *int34x_thermal_zone) | ||
| 266 | { | ||
| 267 | thermal_zone_device_unregister(int34x_thermal_zone->zone); | ||
| 268 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); | ||
| 269 | kfree(int34x_thermal_zone); | ||
| 270 | } | ||
| 271 | EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); | ||
| 272 | |||
| 273 | MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>"); | ||
| 274 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | ||
| 275 | MODULE_DESCRIPTION("Intel INT340x common thermal zone handler"); | ||
| 276 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h new file mode 100644 index 000000000000..9f38ab72c4bf --- /dev/null +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | * int340x_thermal_zone.h | ||
| 3 | * Copyright (c) 2015, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef __INT340X_THERMAL_ZONE_H__ | ||
| 17 | #define __INT340X_THERMAL_ZONE_H__ | ||
| 18 | |||
| 19 | #include <acpi/acpi_lpat.h> | ||
| 20 | |||
| 21 | #define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10 | ||
| 22 | |||
| 23 | struct active_trip { | ||
| 24 | unsigned long temp; | ||
| 25 | int id; | ||
| 26 | bool valid; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct int34x_thermal_zone { | ||
| 30 | struct acpi_device *adev; | ||
| 31 | struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT]; | ||
| 32 | unsigned long *aux_trips; | ||
| 33 | int aux_trip_nr; | ||
| 34 | unsigned long psv_temp; | ||
| 35 | int psv_trip_id; | ||
| 36 | unsigned long crt_temp; | ||
| 37 | int crt_trip_id; | ||
| 38 | unsigned long hot_temp; | ||
| 39 | int hot_trip_id; | ||
| 40 | struct thermal_zone_device *zone; | ||
| 41 | struct thermal_zone_device_ops *override_ops; | ||
| 42 | void *priv_data; | ||
| 43 | struct acpi_lpat_conversion_table *lpat_table; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, | ||
| 47 | struct thermal_zone_device_ops *override_ops); | ||
| 48 | void int340x_thermal_zone_remove(struct int34x_thermal_zone *); | ||
| 49 | |||
| 50 | static inline void int340x_thermal_zone_set_priv_data( | ||
| 51 | struct int34x_thermal_zone *tzone, void *priv_data) | ||
| 52 | { | ||
| 53 | tzone->priv_data = priv_data; | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline void *int340x_thermal_zone_get_priv_data( | ||
| 57 | struct int34x_thermal_zone *tzone) | ||
| 58 | { | ||
| 59 | return tzone->priv_data; | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline void int340x_thermal_zone_device_update( | ||
| 63 | struct int34x_thermal_zone *tzone) | ||
| 64 | { | ||
| 65 | thermal_zone_device_update(tzone->zone); | ||
| 66 | } | ||
| 67 | |||
| 68 | #endif | ||
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 0fe5dbbea968..5e8d8e91ea6d 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/acpi.h> | 20 | #include <linux/acpi.h> |
| 21 | #include <linux/thermal.h> | ||
| 22 | #include "int340x_thermal_zone.h" | ||
| 21 | 23 | ||
| 22 | /* Broadwell-U/HSB thermal reporting device */ | 24 | /* Broadwell-U/HSB thermal reporting device */ |
| 23 | #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 | 25 | #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 |
| @@ -39,6 +41,7 @@ struct proc_thermal_device { | |||
| 39 | struct device *dev; | 41 | struct device *dev; |
| 40 | struct acpi_device *adev; | 42 | struct acpi_device *adev; |
| 41 | struct power_config power_limits[2]; | 43 | struct power_config power_limits[2]; |
| 44 | struct int34x_thermal_zone *int340x_zone; | ||
| 42 | }; | 45 | }; |
| 43 | 46 | ||
| 44 | enum proc_thermal_emum_mode_type { | 47 | enum proc_thermal_emum_mode_type { |
| @@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = { | |||
| 117 | .name = "power_limits" | 120 | .name = "power_limits" |
| 118 | }; | 121 | }; |
| 119 | 122 | ||
| 123 | static int stored_tjmax; /* since it is fixed, we can have local storage */ | ||
| 124 | |||
| 125 | static int get_tjmax(void) | ||
| 126 | { | ||
| 127 | u32 eax, edx; | ||
| 128 | u32 val; | ||
| 129 | int err; | ||
| 130 | |||
| 131 | err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); | ||
| 132 | if (err) | ||
| 133 | return err; | ||
| 134 | |||
| 135 | val = (eax >> 16) & 0xff; | ||
| 136 | if (val) | ||
| 137 | return val; | ||
| 138 | |||
| 139 | return -EINVAL; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int read_temp_msr(unsigned long *temp) | ||
| 143 | { | ||
| 144 | int cpu; | ||
| 145 | u32 eax, edx; | ||
| 146 | int err; | ||
| 147 | unsigned long curr_temp_off = 0; | ||
| 148 | |||
| 149 | *temp = 0; | ||
| 150 | |||
| 151 | for_each_online_cpu(cpu) { | ||
| 152 | err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, | ||
| 153 | &edx); | ||
| 154 | if (err) | ||
| 155 | goto err_ret; | ||
| 156 | else { | ||
| 157 | if (eax & 0x80000000) { | ||
| 158 | curr_temp_off = (eax >> 16) & 0x7f; | ||
| 159 | if (!*temp || curr_temp_off < *temp) | ||
| 160 | *temp = curr_temp_off; | ||
| 161 | } else { | ||
| 162 | err = -EINVAL; | ||
| 163 | goto err_ret; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | return 0; | ||
| 169 | err_ret: | ||
| 170 | return err; | ||
| 171 | } | ||
| 172 | |||
| 173 | static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, | ||
| 174 | unsigned long *temp) | ||
| 175 | { | ||
| 176 | int ret; | ||
| 177 | |||
| 178 | ret = read_temp_msr(temp); | ||
| 179 | if (!ret) | ||
| 180 | *temp = (stored_tjmax - *temp) * 1000; | ||
| 181 | |||
| 182 | return ret; | ||
| 183 | } | ||
| 184 | |||
| 185 | static struct thermal_zone_device_ops proc_thermal_local_ops = { | ||
| 186 | .get_temp = proc_thermal_get_zone_temp, | ||
| 187 | }; | ||
| 188 | |||
| 120 | static int proc_thermal_add(struct device *dev, | 189 | static int proc_thermal_add(struct device *dev, |
| 121 | struct proc_thermal_device **priv) | 190 | struct proc_thermal_device **priv) |
| 122 | { | 191 | { |
| @@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev, | |||
| 126 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | 195 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 127 | union acpi_object *elements, *ppcc; | 196 | union acpi_object *elements, *ppcc; |
| 128 | union acpi_object *p; | 197 | union acpi_object *p; |
| 198 | unsigned long long tmp; | ||
| 199 | struct thermal_zone_device_ops *ops = NULL; | ||
| 129 | int i; | 200 | int i; |
| 130 | int ret; | 201 | int ret; |
| 131 | 202 | ||
| @@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev, | |||
| 178 | 249 | ||
| 179 | ret = sysfs_create_group(&dev->kobj, | 250 | ret = sysfs_create_group(&dev->kobj, |
| 180 | &power_limit_attribute_group); | 251 | &power_limit_attribute_group); |
| 252 | if (ret) | ||
| 253 | goto free_buffer; | ||
| 254 | |||
| 255 | status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); | ||
| 256 | if (ACPI_FAILURE(status)) { | ||
| 257 | /* there is no _TMP method, add local method */ | ||
| 258 | stored_tjmax = get_tjmax(); | ||
| 259 | if (stored_tjmax > 0) | ||
| 260 | ops = &proc_thermal_local_ops; | ||
| 261 | } | ||
| 262 | |||
| 263 | proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); | ||
| 264 | if (IS_ERR(proc_priv->int340x_zone)) { | ||
| 265 | sysfs_remove_group(&proc_priv->dev->kobj, | ||
| 266 | &power_limit_attribute_group); | ||
| 267 | ret = PTR_ERR(proc_priv->int340x_zone); | ||
| 268 | } else | ||
| 269 | ret = 0; | ||
| 181 | 270 | ||
| 182 | free_buffer: | 271 | free_buffer: |
| 183 | kfree(buf.pointer); | 272 | kfree(buf.pointer); |
| @@ -185,8 +274,9 @@ free_buffer: | |||
| 185 | return ret; | 274 | return ret; |
| 186 | } | 275 | } |
| 187 | 276 | ||
| 188 | void proc_thermal_remove(struct proc_thermal_device *proc_priv) | 277 | static void proc_thermal_remove(struct proc_thermal_device *proc_priv) |
| 189 | { | 278 | { |
| 279 | int340x_thermal_zone_remove(proc_priv->int340x_zone); | ||
| 190 | sysfs_remove_group(&proc_priv->dev->kobj, | 280 | sysfs_remove_group(&proc_priv->dev->kobj, |
| 191 | &power_limit_attribute_group); | 281 | &power_limit_attribute_group); |
| 192 | } | 282 | } |
diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index 5580f5b24eb9..9013505e43b7 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c | |||
| @@ -309,10 +309,13 @@ static int soc_dts_enable(int id) | |||
| 309 | return ret; | 309 | return ret; |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) | 312 | static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max, |
| 313 | bool notification_support) | ||
| 313 | { | 314 | { |
| 314 | struct soc_sensor_entry *aux_entry; | 315 | struct soc_sensor_entry *aux_entry; |
| 315 | char name[10]; | 316 | char name[10]; |
| 317 | int trip_count = 0; | ||
| 318 | int trip_mask = 0; | ||
| 316 | int err; | 319 | int err; |
| 317 | 320 | ||
| 318 | aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); | 321 | aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); |
| @@ -332,11 +335,16 @@ static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) | |||
| 332 | aux_entry->tj_max = tj_max; | 335 | aux_entry->tj_max = tj_max; |
| 333 | aux_entry->temp_mask = 0x00FF << (id * 8); | 336 | aux_entry->temp_mask = 0x00FF << (id * 8); |
| 334 | aux_entry->temp_shift = id * 8; | 337 | aux_entry->temp_shift = id * 8; |
| 338 | if (notification_support) { | ||
| 339 | trip_count = SOC_MAX_DTS_TRIPS; | ||
| 340 | trip_mask = 0x02; | ||
| 341 | } | ||
| 335 | snprintf(name, sizeof(name), "soc_dts%d", id); | 342 | snprintf(name, sizeof(name), "soc_dts%d", id); |
| 336 | aux_entry->tzone = thermal_zone_device_register(name, | 343 | aux_entry->tzone = thermal_zone_device_register(name, |
| 337 | SOC_MAX_DTS_TRIPS, | 344 | trip_count, |
| 338 | 0x02, | 345 | trip_mask, |
| 339 | aux_entry, &tzone_ops, NULL, 0, 0); | 346 | aux_entry, &tzone_ops, |
| 347 | NULL, 0, 0); | ||
| 340 | if (IS_ERR(aux_entry->tzone)) { | 348 | if (IS_ERR(aux_entry->tzone)) { |
| 341 | err = PTR_ERR(aux_entry->tzone); | 349 | err = PTR_ERR(aux_entry->tzone); |
| 342 | goto err_ret; | 350 | goto err_ret; |
| @@ -402,6 +410,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) | |||
| 402 | 410 | ||
| 403 | static const struct x86_cpu_id soc_thermal_ids[] = { | 411 | static const struct x86_cpu_id soc_thermal_ids[] = { |
| 404 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, | 412 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, |
| 413 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x4c, 0, 0}, | ||
| 405 | {} | 414 | {} |
| 406 | }; | 415 | }; |
| 407 | MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); | 416 | MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); |
| @@ -420,8 +429,11 @@ static int __init intel_soc_thermal_init(void) | |||
| 420 | if (get_tj_max(&tj_max)) | 429 | if (get_tj_max(&tj_max)) |
| 421 | return -EINVAL; | 430 | return -EINVAL; |
| 422 | 431 | ||
| 432 | soc_dts_thres_irq = (int)match_cpu->driver_data; | ||
| 433 | |||
| 423 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { | 434 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { |
| 424 | soc_dts[i] = alloc_soc_dts(i, tj_max); | 435 | soc_dts[i] = alloc_soc_dts(i, tj_max, |
| 436 | soc_dts_thres_irq ? true : false); | ||
| 425 | if (IS_ERR(soc_dts[i])) { | 437 | if (IS_ERR(soc_dts[i])) { |
| 426 | err = PTR_ERR(soc_dts[i]); | 438 | err = PTR_ERR(soc_dts[i]); |
| 427 | goto err_free; | 439 | goto err_free; |
| @@ -430,15 +442,15 @@ static int __init intel_soc_thermal_init(void) | |||
| 430 | 442 | ||
| 431 | spin_lock_init(&intr_notify_lock); | 443 | spin_lock_init(&intr_notify_lock); |
| 432 | 444 | ||
| 433 | soc_dts_thres_irq = (int)match_cpu->driver_data; | 445 | if (soc_dts_thres_irq) { |
| 434 | 446 | err = request_threaded_irq(soc_dts_thres_irq, NULL, | |
| 435 | err = request_threaded_irq(soc_dts_thres_irq, NULL, | 447 | soc_irq_thread_fn, |
| 436 | soc_irq_thread_fn, | 448 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, |
| 437 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | 449 | "soc_dts", soc_dts); |
| 438 | "soc_dts", soc_dts); | 450 | if (err) { |
| 439 | if (err) { | 451 | pr_err("request_threaded_irq ret %d\n", err); |
| 440 | pr_err("request_threaded_irq ret %d\n", err); | 452 | goto err_free; |
| 441 | goto err_free; | 453 | } |
| 442 | } | 454 | } |
| 443 | 455 | ||
| 444 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { | 456 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { |
| @@ -451,7 +463,8 @@ static int __init intel_soc_thermal_init(void) | |||
| 451 | 463 | ||
| 452 | err_trip_temp: | 464 | err_trip_temp: |
| 453 | i = SOC_MAX_DTS_SENSORS; | 465 | i = SOC_MAX_DTS_SENSORS; |
| 454 | free_irq(soc_dts_thres_irq, soc_dts); | 466 | if (soc_dts_thres_irq) |
| 467 | free_irq(soc_dts_thres_irq, soc_dts); | ||
| 455 | err_free: | 468 | err_free: |
| 456 | while (--i >= 0) | 469 | while (--i >= 0) |
| 457 | free_soc_dts(soc_dts[i]); | 470 | free_soc_dts(soc_dts[i]); |
| @@ -466,7 +479,8 @@ static void __exit intel_soc_thermal_exit(void) | |||
| 466 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) | 479 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) |
| 467 | update_trip_temp(soc_dts[i], 0, 0); | 480 | update_trip_temp(soc_dts[i], 0, 0); |
| 468 | 481 | ||
| 469 | free_irq(soc_dts_thres_irq, soc_dts); | 482 | if (soc_dts_thres_irq) |
| 483 | free_irq(soc_dts_thres_irq, soc_dts); | ||
| 470 | 484 | ||
| 471 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) | 485 | for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) |
| 472 | free_soc_dts(soc_dts[i]); | 486 | free_soc_dts(soc_dts[i]); |
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index fdd1f523a1ed..5a0f12d08e8b 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c | |||
| @@ -45,7 +45,7 @@ | |||
| 45 | * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing | 45 | * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing |
| 46 | * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit, | 46 | * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit, |
| 47 | * if the cooling state already equals lower limit, | 47 | * if the cooling state already equals lower limit, |
| 48 | * deactive the thermal instance | 48 | * deactivate the thermal instance |
| 49 | */ | 49 | */ |
| 50 | static unsigned long get_target_state(struct thermal_instance *instance, | 50 | static unsigned long get_target_state(struct thermal_instance *instance, |
| 51 | enum thermal_trend trend, bool throttle) | 51 | enum thermal_trend trend, bool throttle) |
| @@ -169,7 +169,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) | |||
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | /** | 171 | /** |
| 172 | * step_wise_throttle - throttles devices asscciated with the given zone | 172 | * step_wise_throttle - throttles devices associated with the given zone |
| 173 | * @tz - thermal_zone_device | 173 | * @tz - thermal_zone_device |
| 174 | * @trip - the trip point | 174 | * @trip - the trip point |
| 175 | * @trip_type - type of the trip point | 175 | * @trip_type - type of the trip point |
diff --git a/include/acpi/acpi_lpat.h b/include/acpi/acpi_lpat.h new file mode 100644 index 000000000000..da37e12d23e2 --- /dev/null +++ b/include/acpi/acpi_lpat.h | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | /* | ||
| 2 | * acpi_lpat.h - LPAT table processing functions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2015 Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef ACPI_LPAT_H | ||
| 17 | #define ACPI_LPAT_H | ||
| 18 | |||
| 19 | struct acpi_lpat { | ||
| 20 | int temp; | ||
| 21 | int raw; | ||
| 22 | }; | ||
| 23 | |||
| 24 | struct acpi_lpat_conversion_table { | ||
| 25 | struct acpi_lpat *lpat; | ||
| 26 | int lpat_count; | ||
| 27 | }; | ||
| 28 | |||
| 29 | #ifdef CONFIG_ACPI | ||
| 30 | |||
| 31 | int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, | ||
| 32 | int raw); | ||
| 33 | int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, | ||
| 34 | int temp); | ||
| 35 | struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle | ||
| 36 | handle); | ||
| 37 | void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table | ||
| 38 | *lpat_table); | ||
| 39 | |||
| 40 | #else | ||
| 41 | static int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, | ||
| 42 | int raw) | ||
| 43 | { | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, | ||
| 48 | int temp) | ||
| 49 | { | ||
| 50 | return 0; | ||
| 51 | } | ||
| 52 | |||
| 53 | static struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table( | ||
| 54 | acpi_handle handle) | ||
| 55 | { | ||
| 56 | return NULL; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table | ||
| 60 | *lpat_table) | ||
| 61 | { | ||
| 62 | } | ||
| 63 | |||
| 64 | #endif | ||
| 65 | #endif | ||
