| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * acpi_lpat.c - LPAT table processing functions | 
|---|
| 4 | * | 
|---|
| 5 | * Copyright (C) 2015 Intel Corporation. All rights reserved. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #include <linux/export.h> | 
|---|
| 9 | #include <linux/acpi.h> | 
|---|
| 10 | #include <acpi/acpi_lpat.h> | 
|---|
| 11 |  | 
|---|
| 12 | /** | 
|---|
| 13 | * acpi_lpat_raw_to_temp(): Return temperature from raw value through | 
|---|
| 14 | * LPAT conversion table | 
|---|
| 15 | * | 
|---|
| 16 | * @lpat_table: the temperature_raw mapping table structure | 
|---|
| 17 | * @raw: the raw value, used as a key to get the temperature from the | 
|---|
| 18 | *       above mapping table | 
|---|
| 19 | * | 
|---|
| 20 | * A positive converted temperature value will be returned on success, | 
|---|
| 21 | * a negative errno will be returned in error cases. | 
|---|
| 22 | */ | 
|---|
| 23 | int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, | 
|---|
| 24 | int raw) | 
|---|
| 25 | { | 
|---|
| 26 | int i, delta_temp, delta_raw, temp; | 
|---|
| 27 | struct acpi_lpat *lpat = lpat_table->lpat; | 
|---|
| 28 |  | 
|---|
| 29 | for (i = 0; i < lpat_table->lpat_count - 1; i++) { | 
|---|
| 30 | if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) || | 
|---|
| 31 | (raw <= lpat[i].raw && raw >= lpat[i+1].raw)) | 
|---|
| 32 | break; | 
|---|
| 33 | } | 
|---|
| 34 |  | 
|---|
| 35 | if (i == lpat_table->lpat_count - 1) | 
|---|
| 36 | return -ENOENT; | 
|---|
| 37 |  | 
|---|
| 38 | delta_temp = lpat[i+1].temp - lpat[i].temp; | 
|---|
| 39 | delta_raw = lpat[i+1].raw - lpat[i].raw; | 
|---|
| 40 | temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw; | 
|---|
| 41 |  | 
|---|
| 42 | return temp; | 
|---|
| 43 | } | 
|---|
| 44 | EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp); | 
|---|
| 45 |  | 
|---|
| 46 | /** | 
|---|
| 47 | * acpi_lpat_temp_to_raw(): Return raw value from temperature through | 
|---|
| 48 | * LPAT conversion table | 
|---|
| 49 | * | 
|---|
| 50 | * @lpat_table: the temperature_raw mapping table | 
|---|
| 51 | * @temp: the temperature, used as a key to get the raw value from the | 
|---|
| 52 | *        above mapping table | 
|---|
| 53 | * | 
|---|
| 54 | * The raw value will be returned on success, | 
|---|
| 55 | * a negative errno will be returned in error cases. | 
|---|
| 56 | */ | 
|---|
| 57 | int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, | 
|---|
| 58 | int temp) | 
|---|
| 59 | { | 
|---|
| 60 | int i, delta_temp, delta_raw, raw; | 
|---|
| 61 | struct acpi_lpat *lpat = lpat_table->lpat; | 
|---|
| 62 |  | 
|---|
| 63 | for (i = 0; i < lpat_table->lpat_count - 1; i++) { | 
|---|
| 64 | if (temp >= lpat[i].temp && temp <= lpat[i+1].temp) | 
|---|
| 65 | break; | 
|---|
| 66 | } | 
|---|
| 67 |  | 
|---|
| 68 | if (i ==  lpat_table->lpat_count - 1) | 
|---|
| 69 | return -ENOENT; | 
|---|
| 70 |  | 
|---|
| 71 | delta_temp = lpat[i+1].temp - lpat[i].temp; | 
|---|
| 72 | delta_raw = lpat[i+1].raw - lpat[i].raw; | 
|---|
| 73 | raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp; | 
|---|
| 74 |  | 
|---|
| 75 | return raw; | 
|---|
| 76 | } | 
|---|
| 77 | EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw); | 
|---|
| 78 |  | 
|---|
| 79 | /** | 
|---|
| 80 | * acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present. | 
|---|
| 81 | * | 
|---|
| 82 | * @handle: Handle to acpi device | 
|---|
| 83 | * | 
|---|
| 84 | * Parse LPAT table to a struct of type acpi_lpat_table. On success | 
|---|
| 85 | * it returns a pointer to newly allocated table. This table must | 
|---|
| 86 | * be freed by the caller when finished processing, using a call to | 
|---|
| 87 | * acpi_lpat_free_conversion_table. | 
|---|
| 88 | */ | 
|---|
| 89 | struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle | 
|---|
| 90 | handle) | 
|---|
| 91 | { | 
|---|
| 92 | struct acpi_lpat_conversion_table *lpat_table = NULL; | 
|---|
| 93 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 
|---|
| 94 | union acpi_object *obj_p, *obj_e; | 
|---|
| 95 | int *lpat, i; | 
|---|
| 96 | acpi_status status; | 
|---|
| 97 |  | 
|---|
| 98 | status = acpi_evaluate_object(object: handle, pathname: "LPAT", NULL, return_object_buffer: &buffer); | 
|---|
| 99 | if (ACPI_FAILURE(status)) | 
|---|
| 100 | return NULL; | 
|---|
| 101 |  | 
|---|
| 102 | obj_p = (union acpi_object *)buffer.pointer; | 
|---|
| 103 | if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) || | 
|---|
| 104 | (obj_p->package.count % 2) || (obj_p->package.count < 4)) | 
|---|
| 105 | goto out; | 
|---|
| 106 |  | 
|---|
| 107 | lpat = kcalloc(obj_p->package.count, sizeof(int), GFP_KERNEL); | 
|---|
| 108 | if (!lpat) | 
|---|
| 109 | goto out; | 
|---|
| 110 |  | 
|---|
| 111 | for (i = 0; i < obj_p->package.count; i++) { | 
|---|
| 112 | obj_e = &obj_p->package.elements[i]; | 
|---|
| 113 | if (obj_e->type != ACPI_TYPE_INTEGER) { | 
|---|
| 114 | kfree(objp: lpat); | 
|---|
| 115 | goto out; | 
|---|
| 116 | } | 
|---|
| 117 | lpat[i] = (s64)obj_e->integer.value; | 
|---|
| 118 | } | 
|---|
| 119 |  | 
|---|
| 120 | lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL); | 
|---|
| 121 | if (!lpat_table) { | 
|---|
| 122 | kfree(objp: lpat); | 
|---|
| 123 | goto out; | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|
| 126 | lpat_table->lpat = (struct acpi_lpat *)lpat; | 
|---|
| 127 | lpat_table->lpat_count = obj_p->package.count / 2; | 
|---|
| 128 |  | 
|---|
| 129 | out: | 
|---|
| 130 | kfree(objp: buffer.pointer); | 
|---|
| 131 | return lpat_table; | 
|---|
| 132 | } | 
|---|
| 133 | EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table); | 
|---|
| 134 |  | 
|---|
| 135 | /** | 
|---|
| 136 | * acpi_lpat_free_conversion_table(): Free LPAT table. | 
|---|
| 137 | * | 
|---|
| 138 | * @lpat_table: the temperature_raw mapping table structure | 
|---|
| 139 | * | 
|---|
| 140 | * Frees the LPAT table previously allocated by a call to | 
|---|
| 141 | * acpi_lpat_get_conversion_table. | 
|---|
| 142 | */ | 
|---|
| 143 | void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table | 
|---|
| 144 | *lpat_table) | 
|---|
| 145 | { | 
|---|
| 146 | if (lpat_table) { | 
|---|
| 147 | kfree(objp: lpat_table->lpat); | 
|---|
| 148 | kfree(objp: lpat_table); | 
|---|
| 149 | } | 
|---|
| 150 | } | 
|---|
| 151 | EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table); | 
|---|
| 152 |  | 
|---|