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
= thermal_zone_device_priv(zone
);
18 unsigned long long tmp
;
21 status
= acpi_evaluate_integer(d
->adev
->handle
, "_TMP", NULL
, &tmp
);
22 if (ACPI_FAILURE(status
))
28 conv_temp
= acpi_lpat_raw_to_temp(d
->lpat_table
, (int)tmp
);
32 *temp
= conv_temp
* 10;
34 /* _TMP returns the temperature in tenths of degrees Kelvin */
35 *temp
= deci_kelvin_to_millicelsius(tmp
);
41 static int int340x_thermal_set_trip_temp(struct thermal_zone_device
*zone
,
42 const struct thermal_trip
*trip
, int temp
)
44 struct int34x_thermal_zone
*d
= thermal_zone_device_priv(zone
);
45 unsigned int trip_index
= THERMAL_TRIP_PRIV_TO_INT(trip
->priv
);
46 char name
[] = {'P', 'A', 'T', '0' + trip_index
, '\0'};
52 status
= acpi_execute_simple_method(d
->adev
->handle
, name
,
53 millicelsius_to_deci_kelvin(temp
));
54 if (ACPI_FAILURE(status
))
60 static void int340x_thermal_critical(struct thermal_zone_device
*zone
)
62 dev_dbg(thermal_zone_device(zone
), "%s: critical temperature reached\n",
63 thermal_zone_device_type(zone
));
66 static int int340x_thermal_read_trips(struct acpi_device
*zone_adev
,
67 struct thermal_trip
*zone_trips
,
72 ret
= thermal_acpi_critical_trip_temp(zone_adev
,
73 &zone_trips
[trip_cnt
].temperature
);
75 zone_trips
[trip_cnt
].type
= THERMAL_TRIP_CRITICAL
;
79 ret
= thermal_acpi_hot_trip_temp(zone_adev
,
80 &zone_trips
[trip_cnt
].temperature
);
82 zone_trips
[trip_cnt
].type
= THERMAL_TRIP_HOT
;
86 ret
= thermal_acpi_passive_trip_temp(zone_adev
,
87 &zone_trips
[trip_cnt
].temperature
);
89 zone_trips
[trip_cnt
].type
= THERMAL_TRIP_PASSIVE
;
93 for (i
= 0; i
< INT340X_THERMAL_MAX_ACT_TRIP_COUNT
; i
++) {
94 ret
= thermal_acpi_active_trip_temp(zone_adev
, i
,
95 &zone_trips
[trip_cnt
].temperature
);
99 zone_trips
[trip_cnt
].type
= THERMAL_TRIP_ACTIVE
;
100 zone_trips
[trip_cnt
].priv
= THERMAL_INT_TO_TRIP_PRIV(i
);
107 static struct thermal_zone_params int340x_thermal_params
= {
108 .governor_name
= "user_space",
112 struct int34x_thermal_zone
*int340x_thermal_zone_add(struct acpi_device
*adev
,
113 int (*get_temp
) (struct thermal_zone_device
*, int *))
115 const struct thermal_zone_device_ops zone_ops
= {
116 .set_trip_temp
= int340x_thermal_set_trip_temp
,
117 .critical
= int340x_thermal_critical
,
118 .get_temp
= get_temp
? get_temp
: int340x_thermal_get_zone_temp
,
120 struct int34x_thermal_zone
*int34x_zone
;
121 struct thermal_trip
*zone_trips
;
122 unsigned long long trip_cnt
= 0;
123 unsigned long long hyst
;
127 int34x_zone
= kzalloc(sizeof(*int34x_zone
), GFP_KERNEL
);
129 return ERR_PTR(-ENOMEM
);
131 int34x_zone
->adev
= adev
;
133 status
= acpi_evaluate_integer(adev
->handle
, "PATC", NULL
, &trip_cnt
);
134 if (ACPI_SUCCESS(status
))
135 int34x_zone
->aux_trip_nr
= trip_cnt
;
137 zone_trips
= kzalloc(sizeof(*zone_trips
) * (trip_cnt
+ INT340X_THERMAL_MAX_TRIP_COUNT
),
141 goto err_trips_alloc
;
144 for (i
= 0; i
< trip_cnt
; i
++) {
145 zone_trips
[i
].type
= THERMAL_TRIP_PASSIVE
;
146 zone_trips
[i
].temperature
= THERMAL_TEMP_INVALID
;
147 zone_trips
[i
].flags
|= THERMAL_TRIP_FLAG_RW_TEMP
;
148 zone_trips
[i
].priv
= THERMAL_INT_TO_TRIP_PRIV(i
);
151 trip_cnt
= int340x_thermal_read_trips(adev
, zone_trips
, trip_cnt
);
153 status
= acpi_evaluate_integer(adev
->handle
, "GTSH", NULL
, &hyst
);
154 if (ACPI_SUCCESS(status
))
159 for (i
= 0; i
< trip_cnt
; ++i
)
160 zone_trips
[i
].hysteresis
= hyst
;
162 int34x_zone
->lpat_table
= acpi_lpat_get_conversion_table(adev
->handle
);
164 int34x_zone
->zone
= thermal_zone_device_register_with_trips(
165 acpi_device_bid(adev
),
166 zone_trips
, trip_cnt
,
169 &int340x_thermal_params
,
173 if (IS_ERR(int34x_zone
->zone
)) {
174 ret
= PTR_ERR(int34x_zone
->zone
);
175 goto err_thermal_zone
;
177 ret
= thermal_zone_device_enable(int34x_zone
->zone
);
184 thermal_zone_device_unregister(int34x_zone
->zone
);
186 acpi_lpat_free_conversion_table(int34x_zone
->lpat_table
);
191 EXPORT_SYMBOL_GPL(int340x_thermal_zone_add
);
193 void int340x_thermal_zone_remove(struct int34x_thermal_zone
*int34x_zone
)
195 thermal_zone_device_unregister(int34x_zone
->zone
);
196 acpi_lpat_free_conversion_table(int34x_zone
->lpat_table
);
199 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove
);
201 static int int340x_update_one_trip(struct thermal_trip
*trip
, void *arg
)
203 struct int34x_thermal_zone
*int34x_zone
= arg
;
204 struct acpi_device
*zone_adev
= int34x_zone
->adev
;
207 switch (trip
->type
) {
208 case THERMAL_TRIP_CRITICAL
:
209 err
= thermal_acpi_critical_trip_temp(zone_adev
, &temp
);
211 case THERMAL_TRIP_HOT
:
212 err
= thermal_acpi_hot_trip_temp(zone_adev
, &temp
);
214 case THERMAL_TRIP_PASSIVE
:
215 err
= thermal_acpi_passive_trip_temp(zone_adev
, &temp
);
217 case THERMAL_TRIP_ACTIVE
:
218 err
= thermal_acpi_active_trip_temp(zone_adev
,
219 THERMAL_TRIP_PRIV_TO_INT(trip
->priv
),
226 temp
= THERMAL_TEMP_INVALID
;
228 thermal_zone_set_trip_temp(int34x_zone
->zone
, trip
, temp
);
233 void int340x_thermal_update_trips(struct int34x_thermal_zone
*int34x_zone
)
235 thermal_zone_for_each_trip(int34x_zone
->zone
, int340x_update_one_trip
,
238 EXPORT_SYMBOL_GPL(int340x_thermal_update_trips
);
240 MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
241 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
242 MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
243 MODULE_LICENSE("GPL v2");