]> Git Repo - J-linux.git/blob - drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[J-linux.git] / drivers / thermal / intel / int340x_thermal / int340x_thermal_zone.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * int340x_thermal_zone.c
4  * Copyright (c) 2015, Intel Corporation.
5  */
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"
13
14 static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
15                                          int *temp)
16 {
17         struct int34x_thermal_zone *d = thermal_zone_device_priv(zone);
18         unsigned long long tmp;
19         acpi_status status;
20
21         status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);
22         if (ACPI_FAILURE(status))
23                 return -EIO;
24
25         if (d->lpat_table) {
26                 int conv_temp;
27
28                 conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);
29                 if (conv_temp < 0)
30                         return conv_temp;
31
32                 *temp = conv_temp * 10;
33         } else {
34                 /* _TMP returns the temperature in tenths of degrees Kelvin */
35                 *temp = deci_kelvin_to_millicelsius(tmp);
36         }
37
38         return 0;
39 }
40
41 static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
42                                          int trip, int temp)
43 {
44         struct int34x_thermal_zone *d = thermal_zone_device_priv(zone);
45         char name[] = {'P', 'A', 'T', '0' + trip, '\0'};
46         acpi_status status;
47
48         if (trip > 9)
49                 return -EINVAL;
50
51         status = acpi_execute_simple_method(d->adev->handle, name,
52                                             millicelsius_to_deci_kelvin(temp));
53         if (ACPI_FAILURE(status))
54                 return -EIO;
55
56         return 0;
57 }
58
59 static void int340x_thermal_critical(struct thermal_zone_device *zone)
60 {
61         dev_dbg(&zone->device, "%s: critical temperature reached\n", zone->type);
62 }
63
64 static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
65         .get_temp       = int340x_thermal_get_zone_temp,
66         .set_trip_temp  = int340x_thermal_set_trip_temp,
67         .critical       = int340x_thermal_critical,
68 };
69
70 static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
71                                       struct thermal_trip *zone_trips,
72                                       int trip_cnt)
73 {
74         int i, ret;
75
76         ret = thermal_acpi_critical_trip_temp(zone_adev,
77                                               &zone_trips[trip_cnt].temperature);
78         if (!ret) {
79                 zone_trips[trip_cnt].type = THERMAL_TRIP_CRITICAL;
80                 trip_cnt++;
81         }
82
83         ret = thermal_acpi_hot_trip_temp(zone_adev,
84                                          &zone_trips[trip_cnt].temperature);
85         if (!ret) {
86                 zone_trips[trip_cnt].type = THERMAL_TRIP_HOT;
87                 trip_cnt++;
88         }
89
90         ret = thermal_acpi_passive_trip_temp(zone_adev,
91                                              &zone_trips[trip_cnt].temperature);
92         if (!ret) {
93                 zone_trips[trip_cnt].type = THERMAL_TRIP_PASSIVE;
94                 trip_cnt++;
95         }
96
97         for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
98                 ret = thermal_acpi_active_trip_temp(zone_adev, i,
99                                                     &zone_trips[trip_cnt].temperature);
100                 if (ret)
101                         break;
102
103                 zone_trips[trip_cnt].type = THERMAL_TRIP_ACTIVE;
104                 trip_cnt++;
105         }
106
107         return trip_cnt;
108 }
109
110 static struct thermal_zone_params int340x_thermal_params = {
111         .governor_name = "user_space",
112         .no_hwmon = true,
113 };
114
115 struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
116                                                      int (*get_temp) (struct thermal_zone_device *, int *))
117 {
118         struct int34x_thermal_zone *int34x_zone;
119         struct thermal_trip *zone_trips;
120         unsigned long long trip_cnt = 0;
121         unsigned long long hyst;
122         int trip_mask = 0;
123         acpi_status status;
124         int i, ret;
125
126         int34x_zone = kzalloc(sizeof(*int34x_zone), GFP_KERNEL);
127         if (!int34x_zone)
128                 return ERR_PTR(-ENOMEM);
129
130         int34x_zone->adev = adev;
131
132         int34x_zone->ops = kmemdup(&int340x_thermal_zone_ops,
133                                    sizeof(int340x_thermal_zone_ops), GFP_KERNEL);
134         if (!int34x_zone->ops) {
135                 ret = -ENOMEM;
136                 goto err_ops_alloc;
137         }
138
139         if (get_temp)
140                 int34x_zone->ops->get_temp = get_temp;
141
142         status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
143         if (ACPI_SUCCESS(status)) {
144                 int34x_zone->aux_trip_nr = trip_cnt;
145                 trip_mask = BIT(trip_cnt) - 1;
146         }
147
148         zone_trips = kzalloc(sizeof(*zone_trips) * (trip_cnt + INT340X_THERMAL_MAX_TRIP_COUNT),
149                              GFP_KERNEL);
150         if (!zone_trips) {
151                 ret = -ENOMEM;
152                 goto err_trips_alloc;
153         }
154
155         for (i = 0; i < trip_cnt; i++) {
156                 zone_trips[i].type = THERMAL_TRIP_PASSIVE;
157                 zone_trips[i].temperature = THERMAL_TEMP_INVALID;
158         }
159
160         trip_cnt = int340x_thermal_read_trips(adev, zone_trips, trip_cnt);
161
162         status = acpi_evaluate_integer(adev->handle, "GTSH", NULL, &hyst);
163         if (ACPI_SUCCESS(status))
164                 hyst *= 100;
165         else
166                 hyst = 0;
167
168         for (i = 0; i < trip_cnt; ++i)
169                 zone_trips[i].hysteresis = hyst;
170
171         int34x_zone->trips = zone_trips;
172
173         int34x_zone->lpat_table = acpi_lpat_get_conversion_table(adev->handle);
174
175         int34x_zone->zone = thermal_zone_device_register_with_trips(
176                                                         acpi_device_bid(adev),
177                                                         zone_trips, trip_cnt,
178                                                         trip_mask, int34x_zone,
179                                                         int34x_zone->ops,
180                                                         &int340x_thermal_params,
181                                                         0, 0);
182         if (IS_ERR(int34x_zone->zone)) {
183                 ret = PTR_ERR(int34x_zone->zone);
184                 goto err_thermal_zone;
185         }
186         ret = thermal_zone_device_enable(int34x_zone->zone);
187         if (ret)
188                 goto err_enable;
189
190         return int34x_zone;
191
192 err_enable:
193         thermal_zone_device_unregister(int34x_zone->zone);
194 err_thermal_zone:
195         kfree(int34x_zone->trips);
196         acpi_lpat_free_conversion_table(int34x_zone->lpat_table);
197 err_trips_alloc:
198         kfree(int34x_zone->ops);
199 err_ops_alloc:
200         kfree(int34x_zone);
201         return ERR_PTR(ret);
202 }
203 EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);
204
205 void int340x_thermal_zone_remove(struct int34x_thermal_zone *int34x_zone)
206 {
207         thermal_zone_device_unregister(int34x_zone->zone);
208         acpi_lpat_free_conversion_table(int34x_zone->lpat_table);
209         kfree(int34x_zone->trips);
210         kfree(int34x_zone->ops);
211         kfree(int34x_zone);
212 }
213 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
214
215 void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone)
216 {
217         struct acpi_device *zone_adev = int34x_zone->adev;
218         struct thermal_trip *zone_trips = int34x_zone->trips;
219         int trip_cnt = int34x_zone->zone->num_trips;
220         int act_trip_nr = 0;
221         int i;
222
223         mutex_lock(&int34x_zone->zone->lock);
224
225         for (i = int34x_zone->aux_trip_nr; i < trip_cnt; i++) {
226                 int temp, err;
227
228                 switch (zone_trips[i].type) {
229                 case THERMAL_TRIP_CRITICAL:
230                         err = thermal_acpi_critical_trip_temp(zone_adev, &temp);
231                         break;
232                 case THERMAL_TRIP_HOT:
233                         err = thermal_acpi_hot_trip_temp(zone_adev, &temp);
234                         break;
235                 case THERMAL_TRIP_PASSIVE:
236                         err = thermal_acpi_passive_trip_temp(zone_adev, &temp);
237                         break;
238                 case THERMAL_TRIP_ACTIVE:
239                         err = thermal_acpi_active_trip_temp(zone_adev, act_trip_nr++,
240                                                             &temp);
241                         break;
242                 default:
243                         err = -ENODEV;
244                 }
245                 if (err) {
246                         zone_trips[i].temperature = THERMAL_TEMP_INVALID;
247                         continue;
248                 }
249
250                 zone_trips[i].temperature = temp;
251         }
252
253         mutex_unlock(&int34x_zone->zone->lock);
254 }
255 EXPORT_SYMBOL_GPL(int340x_thermal_update_trips);
256
257 MODULE_AUTHOR("Aaron Lu <[email protected]>");
258 MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
259 MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
260 MODULE_LICENSE("GPL v2");
This page took 0.042757 seconds and 4 git commands to generate.