blob: 0dbe0060f86e2647fb7af62e19350cce3ee11f77 [file] [log] [blame]
Ben Skeggsb9ed9192013-10-15 09:44:02 +10001/*
2 * Copyright 2010 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#ifdef CONFIG_ACPI
26#include <linux/acpi.h>
27#endif
28#include <linux/power_supply.h>
29#include <linux/hwmon.h>
30#include <linux/hwmon-sysfs.h>
31
32#include <drm/drmP.h>
33
34#include "nouveau_drm.h"
35#include "nouveau_hwmon.h"
36
Ben Skeggsb9ed9192013-10-15 09:44:02 +100037#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
38static ssize_t
39nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
40{
41 struct drm_device *dev = dev_get_drvdata(d);
42 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +100043 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +100044 int temp = therm->temp_get(therm);
45
46 if (temp < 0)
47 return temp;
48
49 return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000);
50}
51static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
52 NULL, 0);
53
54static ssize_t
55nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d,
56 struct device_attribute *a, char *buf)
57{
58 return snprintf(buf, PAGE_SIZE, "%d\n", 100);
59}
60static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO,
61 nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0);
62
63static ssize_t
64nouveau_hwmon_temp1_auto_point1_temp(struct device *d,
65 struct device_attribute *a, char *buf)
66{
67 struct drm_device *dev = dev_get_drvdata(d);
68 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +100069 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +100070
71 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +100072 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +100073}
74static ssize_t
75nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d,
76 struct device_attribute *a,
77 const char *buf, size_t count)
78{
79 struct drm_device *dev = dev_get_drvdata(d);
80 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +100081 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +100082 long value;
83
84 if (kstrtol(buf, 10, &value) == -EINVAL)
85 return count;
86
Ben Skeggse1404612015-01-14 15:11:48 +100087 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST,
Ben Skeggsb9ed9192013-10-15 09:44:02 +100088 value / 1000);
89
90 return count;
91}
92static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO | S_IWUSR,
93 nouveau_hwmon_temp1_auto_point1_temp,
94 nouveau_hwmon_set_temp1_auto_point1_temp, 0);
95
96static ssize_t
97nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d,
98 struct device_attribute *a, char *buf)
99{
100 struct drm_device *dev = dev_get_drvdata(d);
101 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000102 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000103
104 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +1000105 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000106}
107static ssize_t
108nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d,
109 struct device_attribute *a,
110 const char *buf, size_t count)
111{
112 struct drm_device *dev = dev_get_drvdata(d);
113 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000114 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000115 long value;
116
117 if (kstrtol(buf, 10, &value) == -EINVAL)
118 return count;
119
Ben Skeggse1404612015-01-14 15:11:48 +1000120 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST,
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000121 value / 1000);
122
123 return count;
124}
125static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
126 nouveau_hwmon_temp1_auto_point1_temp_hyst,
127 nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0);
128
129static ssize_t
130nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
131{
132 struct drm_device *dev = dev_get_drvdata(d);
133 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000134 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000135
136 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +1000137 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000138}
139static ssize_t
140nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
141 const char *buf, size_t count)
142{
143 struct drm_device *dev = dev_get_drvdata(d);
144 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000145 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000146 long value;
147
148 if (kstrtol(buf, 10, &value) == -EINVAL)
149 return count;
150
Ben Skeggse1404612015-01-14 15:11:48 +1000151 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000152
153 return count;
154}
155static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
156 nouveau_hwmon_set_max_temp,
157 0);
158
159static ssize_t
160nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a,
161 char *buf)
162{
163 struct drm_device *dev = dev_get_drvdata(d);
164 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000165 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000166
167 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +1000168 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000169}
170static ssize_t
171nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a,
172 const char *buf, size_t count)
173{
174 struct drm_device *dev = dev_get_drvdata(d);
175 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000176 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000177 long value;
178
179 if (kstrtol(buf, 10, &value) == -EINVAL)
180 return count;
181
Ben Skeggse1404612015-01-14 15:11:48 +1000182 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST,
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000183 value / 1000);
184
185 return count;
186}
187static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
188 nouveau_hwmon_max_temp_hyst,
189 nouveau_hwmon_set_max_temp_hyst, 0);
190
191static ssize_t
192nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
193 char *buf)
194{
195 struct drm_device *dev = dev_get_drvdata(d);
196 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000197 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000198
199 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +1000200 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000201}
202static ssize_t
203nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
204 const char *buf,
205 size_t count)
206{
207 struct drm_device *dev = dev_get_drvdata(d);
208 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000209 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000210 long value;
211
212 if (kstrtol(buf, 10, &value) == -EINVAL)
213 return count;
214
Ben Skeggse1404612015-01-14 15:11:48 +1000215 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, value / 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000216
217 return count;
218}
219static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
220 nouveau_hwmon_critical_temp,
221 nouveau_hwmon_set_critical_temp,
222 0);
223
224static ssize_t
225nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a,
226 char *buf)
227{
228 struct drm_device *dev = dev_get_drvdata(d);
229 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000230 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000231
232 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +1000233 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000234}
235static ssize_t
236nouveau_hwmon_set_critical_temp_hyst(struct device *d,
237 struct device_attribute *a,
238 const char *buf,
239 size_t count)
240{
241 struct drm_device *dev = dev_get_drvdata(d);
242 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000243 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000244 long value;
245
246 if (kstrtol(buf, 10, &value) == -EINVAL)
247 return count;
248
Ben Skeggse1404612015-01-14 15:11:48 +1000249 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST,
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000250 value / 1000);
251
252 return count;
253}
254static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR,
255 nouveau_hwmon_critical_temp_hyst,
256 nouveau_hwmon_set_critical_temp_hyst, 0);
257static ssize_t
258nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a,
259 char *buf)
260{
261 struct drm_device *dev = dev_get_drvdata(d);
262 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000263 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000264
265 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +1000266 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000267}
268static ssize_t
269nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a,
270 const char *buf,
271 size_t count)
272{
273 struct drm_device *dev = dev_get_drvdata(d);
274 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000275 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000276 long value;
277
278 if (kstrtol(buf, 10, &value) == -EINVAL)
279 return count;
280
Ben Skeggse1404612015-01-14 15:11:48 +1000281 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, value / 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000282
283 return count;
284}
285static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO | S_IWUSR,
286 nouveau_hwmon_emergency_temp,
287 nouveau_hwmon_set_emergency_temp,
288 0);
289
290static ssize_t
291nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a,
292 char *buf)
293{
294 struct drm_device *dev = dev_get_drvdata(d);
295 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000296 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000297
298 return snprintf(buf, PAGE_SIZE, "%d\n",
Ben Skeggse1404612015-01-14 15:11:48 +1000299 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000300}
301static ssize_t
302nouveau_hwmon_set_emergency_temp_hyst(struct device *d,
303 struct device_attribute *a,
304 const char *buf,
305 size_t count)
306{
307 struct drm_device *dev = dev_get_drvdata(d);
308 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000309 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000310 long value;
311
312 if (kstrtol(buf, 10, &value) == -EINVAL)
313 return count;
314
Ben Skeggse1404612015-01-14 15:11:48 +1000315 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST,
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000316 value / 1000);
317
318 return count;
319}
320static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO | S_IWUSR,
321 nouveau_hwmon_emergency_temp_hyst,
322 nouveau_hwmon_set_emergency_temp_hyst,
323 0);
324
325static ssize_t nouveau_hwmon_show_name(struct device *dev,
326 struct device_attribute *attr,
327 char *buf)
328{
329 return sprintf(buf, "nouveau\n");
330}
331static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
332
333static ssize_t nouveau_hwmon_show_update_rate(struct device *dev,
334 struct device_attribute *attr,
335 char *buf)
336{
337 return sprintf(buf, "1000\n");
338}
339static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
340 nouveau_hwmon_show_update_rate,
341 NULL, 0);
342
343static ssize_t
344nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr,
345 char *buf)
346{
347 struct drm_device *dev = dev_get_drvdata(d);
348 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000349 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000350
351 return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
352}
353static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input,
354 NULL, 0);
355
356 static ssize_t
357nouveau_hwmon_get_pwm1_enable(struct device *d,
358 struct device_attribute *a, char *buf)
359{
360 struct drm_device *dev = dev_get_drvdata(d);
361 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000362 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000363 int ret;
364
Ben Skeggse1404612015-01-14 15:11:48 +1000365 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000366 if (ret < 0)
367 return ret;
368
369 return sprintf(buf, "%i\n", ret);
370}
371
372static ssize_t
373nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
374 const char *buf, size_t count)
375{
376 struct drm_device *dev = dev_get_drvdata(d);
377 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000378 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000379 long value;
380 int ret;
381
Jingoo Han0ac4e3a2014-02-05 11:02:59 +0900382 ret = kstrtol(buf, 10, &value);
383 if (ret)
384 return ret;
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000385
Ben Skeggse1404612015-01-14 15:11:48 +1000386 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, value);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000387 if (ret)
388 return ret;
389 else
390 return count;
391}
392static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
393 nouveau_hwmon_get_pwm1_enable,
394 nouveau_hwmon_set_pwm1_enable, 0);
395
396static ssize_t
397nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf)
398{
399 struct drm_device *dev = dev_get_drvdata(d);
400 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000401 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000402 int ret;
403
404 ret = therm->fan_get(therm);
405 if (ret < 0)
406 return ret;
407
408 return sprintf(buf, "%i\n", ret);
409}
410
411static ssize_t
412nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a,
413 const char *buf, size_t count)
414{
415 struct drm_device *dev = dev_get_drvdata(d);
416 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000417 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000418 int ret = -ENODEV;
419 long value;
420
421 if (kstrtol(buf, 10, &value) == -EINVAL)
422 return -EINVAL;
423
424 ret = therm->fan_set(therm, value);
425 if (ret)
426 return ret;
427
428 return count;
429}
430
431static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,
432 nouveau_hwmon_get_pwm1,
433 nouveau_hwmon_set_pwm1, 0);
434
435static ssize_t
436nouveau_hwmon_get_pwm1_min(struct device *d,
437 struct device_attribute *a, char *buf)
438{
439 struct drm_device *dev = dev_get_drvdata(d);
440 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000441 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000442 int ret;
443
Ben Skeggse1404612015-01-14 15:11:48 +1000444 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000445 if (ret < 0)
446 return ret;
447
448 return sprintf(buf, "%i\n", ret);
449}
450
451static ssize_t
452nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a,
453 const char *buf, size_t count)
454{
455 struct drm_device *dev = dev_get_drvdata(d);
456 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000457 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000458 long value;
459 int ret;
460
461 if (kstrtol(buf, 10, &value) == -EINVAL)
462 return -EINVAL;
463
Ben Skeggse1404612015-01-14 15:11:48 +1000464 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY, value);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000465 if (ret < 0)
466 return ret;
467
468 return count;
469}
470
471static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR,
472 nouveau_hwmon_get_pwm1_min,
473 nouveau_hwmon_set_pwm1_min, 0);
474
475static ssize_t
476nouveau_hwmon_get_pwm1_max(struct device *d,
477 struct device_attribute *a, char *buf)
478{
479 struct drm_device *dev = dev_get_drvdata(d);
480 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000481 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000482 int ret;
483
Ben Skeggse1404612015-01-14 15:11:48 +1000484 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000485 if (ret < 0)
486 return ret;
487
488 return sprintf(buf, "%i\n", ret);
489}
490
491static ssize_t
492nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a,
493 const char *buf, size_t count)
494{
495 struct drm_device *dev = dev_get_drvdata(d);
496 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000497 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000498 long value;
499 int ret;
500
501 if (kstrtol(buf, 10, &value) == -EINVAL)
502 return -EINVAL;
503
Ben Skeggse1404612015-01-14 15:11:48 +1000504 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY, value);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000505 if (ret < 0)
506 return ret;
507
508 return count;
509}
510
511static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR,
512 nouveau_hwmon_get_pwm1_max,
513 nouveau_hwmon_set_pwm1_max, 0);
514
515static struct attribute *hwmon_default_attributes[] = {
516 &sensor_dev_attr_name.dev_attr.attr,
517 &sensor_dev_attr_update_rate.dev_attr.attr,
518 NULL
519};
520static struct attribute *hwmon_temp_attributes[] = {
521 &sensor_dev_attr_temp1_input.dev_attr.attr,
522 &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr,
523 &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
524 &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
525 &sensor_dev_attr_temp1_max.dev_attr.attr,
526 &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
527 &sensor_dev_attr_temp1_crit.dev_attr.attr,
528 &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
529 &sensor_dev_attr_temp1_emergency.dev_attr.attr,
530 &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr,
531 NULL
532};
533static struct attribute *hwmon_fan_rpm_attributes[] = {
534 &sensor_dev_attr_fan1_input.dev_attr.attr,
535 NULL
536};
537static struct attribute *hwmon_pwm_fan_attributes[] = {
538 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
539 &sensor_dev_attr_pwm1.dev_attr.attr,
540 &sensor_dev_attr_pwm1_min.dev_attr.attr,
541 &sensor_dev_attr_pwm1_max.dev_attr.attr,
542 NULL
543};
544
545static const struct attribute_group hwmon_default_attrgroup = {
546 .attrs = hwmon_default_attributes,
547};
548static const struct attribute_group hwmon_temp_attrgroup = {
549 .attrs = hwmon_temp_attributes,
550};
551static const struct attribute_group hwmon_fan_rpm_attrgroup = {
552 .attrs = hwmon_fan_rpm_attributes,
553};
554static const struct attribute_group hwmon_pwm_fan_attrgroup = {
555 .attrs = hwmon_pwm_fan_attributes,
556};
557#endif
558
559int
560nouveau_hwmon_init(struct drm_device *dev)
561{
562#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
563 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000564 struct nvkm_therm *therm = nvxx_therm(&drm->device);
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000565 struct nouveau_hwmon *hwmon;
566 struct device *hwmon_dev;
567 int ret = 0;
568
569 hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);
570 if (!hwmon)
571 return -ENOMEM;
572 hwmon->dev = dev;
573
574 if (!therm || !therm->temp_get || !therm->attr_get || !therm->attr_set)
575 return -ENODEV;
576
577 hwmon_dev = hwmon_device_register(&dev->pdev->dev);
578 if (IS_ERR(hwmon_dev)) {
579 ret = PTR_ERR(hwmon_dev);
580 NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret);
581 return ret;
582 }
583 dev_set_drvdata(hwmon_dev, dev);
584
585 /* set the default attributes */
586 ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup);
Dan Carpenteraa34efe2014-02-06 12:29:43 +0300587 if (ret)
588 goto error;
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000589
590 /* if the card has a working thermal sensor */
591 if (therm->temp_get(therm) >= 0) {
592 ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup);
Dan Carpenteraa34efe2014-02-06 12:29:43 +0300593 if (ret)
594 goto error;
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000595 }
596
597 /* if the card has a pwm fan */
598 /*XXX: incorrect, need better detection for this, some boards have
599 * the gpio entries for pwm fan control even when there's no
600 * actual fan connected to it... therm table? */
601 if (therm->fan_get && therm->fan_get(therm) >= 0) {
602 ret = sysfs_create_group(&hwmon_dev->kobj,
603 &hwmon_pwm_fan_attrgroup);
604 if (ret)
605 goto error;
606 }
607
608 /* if the card can read the fan rpm */
609 if (therm->fan_sense(therm) >= 0) {
610 ret = sysfs_create_group(&hwmon_dev->kobj,
611 &hwmon_fan_rpm_attrgroup);
612 if (ret)
613 goto error;
614 }
615
616 hwmon->hwmon = hwmon_dev;
617
618 return 0;
619
620error:
621 NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret);
622 hwmon_device_unregister(hwmon_dev);
623 hwmon->hwmon = NULL;
624 return ret;
625#else
Ben Skeggsb9ed9192013-10-15 09:44:02 +1000626 return 0;
627#endif
628}
629
630void
631nouveau_hwmon_fini(struct drm_device *dev)
632{
633#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
634 struct nouveau_hwmon *hwmon = nouveau_hwmon(dev);
635
636 if (hwmon->hwmon) {
637 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_default_attrgroup);
638 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_temp_attrgroup);
639 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_pwm_fan_attrgroup);
640 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_fan_rpm_attrgroup);
641
642 hwmon_device_unregister(hwmon->hwmon);
643 }
644
645 nouveau_drm(dev)->hwmon = NULL;
646 kfree(hwmon);
647#endif
648}