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