1 // SPDX-License-Identifier: GPL-2.0-only
3 * int340x_thermal_zone.c
4 * Copyright (c) 2015, Intel Corporation.
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/init.h>
9 #include <linux/acpi.h>
10 #include <linux/thermal.h>
11 #include <linux/units.h>
12 #include "int340x_thermal_zone.h"
14 static int int340x_thermal_get_zone_temp(struct thermal_zone_device
*zone
,
17 struct int34x_thermal_zone
*d
= zone
->devdata
;
18 unsigned long long tmp
;
21 if (d
->override_ops
&& d
->override_ops
->get_temp
)
22 return d
->override_ops
->get_temp(zone
, temp
);
24 status
= acpi_evaluate_integer(d
->adev
->handle
, "_TMP", NULL
, &tmp
);
25 if (ACPI_FAILURE(status
))
31 conv_temp
= acpi_lpat_raw_to_temp(d
->lpat_table
, (int)tmp
);
35 *temp
= (unsigned long)conv_temp
* 10;
37 /* _TMP returns the temperature in tenths of degrees Kelvin */
38 *temp
= deci_kelvin_to_millicelsius(tmp
);
43 static int int340x_thermal_get_trip_temp(struct thermal_zone_device
*zone
,
46 struct int34x_thermal_zone
*d
= zone
->devdata
;
49 if (d
->override_ops
&& d
->override_ops
->get_trip_temp
)
50 return d
->override_ops
->get_trip_temp(zone
, trip
, temp
);
52 if (trip
< d
->aux_trip_nr
)
53 *temp
= d
->aux_trips
[trip
];
54 else if (trip
== d
->crt_trip_id
)
56 else if (trip
== d
->psv_trip_id
)
58 else if (trip
== d
->hot_trip_id
)
61 for (i
= 0; i
< INT340X_THERMAL_MAX_ACT_TRIP_COUNT
; i
++) {
62 if (d
->act_trips
[i
].valid
&&
63 d
->act_trips
[i
].id
== trip
) {
64 *temp
= d
->act_trips
[i
].temp
;
68 if (i
== INT340X_THERMAL_MAX_ACT_TRIP_COUNT
)
75 static int int340x_thermal_get_trip_type(struct thermal_zone_device
*zone
,
77 enum thermal_trip_type
*type
)
79 struct int34x_thermal_zone
*d
= zone
->devdata
;
82 if (d
->override_ops
&& d
->override_ops
->get_trip_type
)
83 return d
->override_ops
->get_trip_type(zone
, trip
, type
);
85 if (trip
< d
->aux_trip_nr
)
86 *type
= THERMAL_TRIP_PASSIVE
;
87 else if (trip
== d
->crt_trip_id
)
88 *type
= THERMAL_TRIP_CRITICAL
;
89 else if (trip
== d
->hot_trip_id
)
90 *type
= THERMAL_TRIP_HOT
;
91 else if (trip
== d
->psv_trip_id
)
92 *type
= THERMAL_TRIP_PASSIVE
;
94 for (i
= 0; i
< INT340X_THERMAL_MAX_ACT_TRIP_COUNT
; i
++) {
95 if (d
->act_trips
[i
].valid
&&
96 d
->act_trips
[i
].id
== trip
) {
97 *type
= THERMAL_TRIP_ACTIVE
;
101 if (i
== INT340X_THERMAL_MAX_ACT_TRIP_COUNT
)
108 static int int340x_thermal_set_trip_temp(struct thermal_zone_device
*zone
,
111 struct int34x_thermal_zone
*d
= zone
->devdata
;
115 if (d
->override_ops
&& d
->override_ops
->set_trip_temp
)
116 return d
->override_ops
->set_trip_temp(zone
, trip
, temp
);
118 snprintf(name
, sizeof(name
), "PAT%d", trip
);
119 status
= acpi_execute_simple_method(d
->adev
->handle
, name
,
120 millicelsius_to_deci_kelvin(temp
));
121 if (ACPI_FAILURE(status
))
124 d
->aux_trips
[trip
] = temp
;
130 static int int340x_thermal_get_trip_hyst(struct thermal_zone_device
*zone
,
133 struct int34x_thermal_zone
*d
= zone
->devdata
;
135 unsigned long long hyst
;
137 if (d
->override_ops
&& d
->override_ops
->get_trip_hyst
)
138 return d
->override_ops
->get_trip_hyst(zone
, trip
, temp
);
140 status
= acpi_evaluate_integer(d
->adev
->handle
, "GTSH", NULL
, &hyst
);
141 if (ACPI_FAILURE(status
))
149 static struct thermal_zone_device_ops int340x_thermal_zone_ops
= {
150 .get_temp
= int340x_thermal_get_zone_temp
,
151 .get_trip_temp
= int340x_thermal_get_trip_temp
,
152 .get_trip_type
= int340x_thermal_get_trip_type
,
153 .set_trip_temp
= int340x_thermal_set_trip_temp
,
154 .get_trip_hyst
= int340x_thermal_get_trip_hyst
,
157 static int int340x_thermal_get_trip_config(acpi_handle handle
, char *name
,
160 unsigned long long r
;
163 status
= acpi_evaluate_integer(handle
, name
, NULL
, &r
);
164 if (ACPI_FAILURE(status
))
167 *temp
= deci_kelvin_to_millicelsius(r
);
172 int int340x_thermal_read_trips(struct int34x_thermal_zone
*int34x_zone
)
174 int trip_cnt
= int34x_zone
->aux_trip_nr
;
177 int34x_zone
->crt_trip_id
= -1;
178 if (!int340x_thermal_get_trip_config(int34x_zone
->adev
->handle
, "_CRT",
179 &int34x_zone
->crt_temp
))
180 int34x_zone
->crt_trip_id
= trip_cnt
++;
182 int34x_zone
->hot_trip_id
= -1;
183 if (!int340x_thermal_get_trip_config(int34x_zone
->adev
->handle
, "_HOT",
184 &int34x_zone
->hot_temp
))
185 int34x_zone
->hot_trip_id
= trip_cnt
++;
187 int34x_zone
->psv_trip_id
= -1;
188 if (!int340x_thermal_get_trip_config(int34x_zone
->adev
->handle
, "_PSV",
189 &int34x_zone
->psv_temp
))
190 int34x_zone
->psv_trip_id
= trip_cnt
++;
192 for (i
= 0; i
< INT340X_THERMAL_MAX_ACT_TRIP_COUNT
; i
++) {
193 char name
[5] = { '_', 'A', 'C', '0' + i
, '\0' };
195 if (int340x_thermal_get_trip_config(int34x_zone
->adev
->handle
,
197 &int34x_zone
->act_trips
[i
].temp
))
200 int34x_zone
->act_trips
[i
].id
= trip_cnt
++;
201 int34x_zone
->act_trips
[i
].valid
= true;
206 EXPORT_SYMBOL_GPL(int340x_thermal_read_trips
);
208 static struct thermal_zone_params int340x_thermal_params
= {
209 .governor_name
= "user_space",
213 struct int34x_thermal_zone
*int340x_thermal_zone_add(struct acpi_device
*adev
,
214 struct thermal_zone_device_ops
*override_ops
)
216 struct int34x_thermal_zone
*int34x_thermal_zone
;
218 unsigned long long trip_cnt
;
222 int34x_thermal_zone
= kzalloc(sizeof(*int34x_thermal_zone
),
224 if (!int34x_thermal_zone
)
225 return ERR_PTR(-ENOMEM
);
227 int34x_thermal_zone
->adev
= adev
;
228 int34x_thermal_zone
->override_ops
= override_ops
;
230 status
= acpi_evaluate_integer(adev
->handle
, "PATC", NULL
, &trip_cnt
);
231 if (ACPI_FAILURE(status
))
234 int34x_thermal_zone
->aux_trips
=
236 sizeof(*int34x_thermal_zone
->aux_trips
),
238 if (!int34x_thermal_zone
->aux_trips
) {
242 trip_mask
= BIT(trip_cnt
) - 1;
243 int34x_thermal_zone
->aux_trip_nr
= trip_cnt
;
246 trip_cnt
= int340x_thermal_read_trips(int34x_thermal_zone
);
248 int34x_thermal_zone
->lpat_table
= acpi_lpat_get_conversion_table(
251 int34x_thermal_zone
->zone
= thermal_zone_device_register(
252 acpi_device_bid(adev
),
254 trip_mask
, int34x_thermal_zone
,
255 &int340x_thermal_zone_ops
,
256 &int340x_thermal_params
,
258 if (IS_ERR(int34x_thermal_zone
->zone
)) {
259 ret
= PTR_ERR(int34x_thermal_zone
->zone
);
260 goto err_thermal_zone
;
263 return int34x_thermal_zone
;
266 acpi_lpat_free_conversion_table(int34x_thermal_zone
->lpat_table
);
267 kfree(int34x_thermal_zone
->aux_trips
);
269 kfree(int34x_thermal_zone
);
272 EXPORT_SYMBOL_GPL(int340x_thermal_zone_add
);
274 void int340x_thermal_zone_remove(struct int34x_thermal_zone
275 *int34x_thermal_zone
)
277 thermal_zone_device_unregister(int34x_thermal_zone
->zone
);
278 acpi_lpat_free_conversion_table(int34x_thermal_zone
->lpat_table
);
279 kfree(int34x_thermal_zone
->aux_trips
);
280 kfree(int34x_thermal_zone
);
282 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove
);
284 MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
285 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
286 MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
287 MODULE_LICENSE("GPL v2");