1 | /* $NetBSD: nouveau_hwmon.c,v 1.1.1.2 2014/08/06 12:36:23 riastradh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright 2010 Red Hat Inc. |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the "Software"), |
8 | * to deal in the Software without restriction, including without limitation |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
10 | * and/or sell copies of the Software, and to permit persons to whom the |
11 | * Software is furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
22 | * OTHER DEALINGS IN THE SOFTWARE. |
23 | * |
24 | * Authors: Ben Skeggs |
25 | */ |
26 | |
27 | #include <sys/cdefs.h> |
28 | __KERNEL_RCSID(0, "$NetBSD: nouveau_hwmon.c,v 1.1.1.2 2014/08/06 12:36:23 riastradh Exp $" ); |
29 | |
30 | #ifdef CONFIG_ACPI |
31 | #include <linux/acpi.h> |
32 | #endif |
33 | #include <linux/power_supply.h> |
34 | #include <linux/hwmon.h> |
35 | #include <linux/hwmon-sysfs.h> |
36 | |
37 | #include <drm/drmP.h> |
38 | |
39 | #include "nouveau_drm.h" |
40 | #include "nouveau_hwmon.h" |
41 | |
42 | #include <subdev/gpio.h> |
43 | #include <subdev/timer.h> |
44 | #include <subdev/therm.h> |
45 | |
46 | #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) |
47 | static ssize_t |
48 | nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) |
49 | { |
50 | struct drm_device *dev = dev_get_drvdata(d); |
51 | struct nouveau_drm *drm = nouveau_drm(dev); |
52 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
53 | int temp = therm->temp_get(therm); |
54 | |
55 | if (temp < 0) |
56 | return temp; |
57 | |
58 | return snprintf(buf, PAGE_SIZE, "%d\n" , temp * 1000); |
59 | } |
60 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, |
61 | NULL, 0); |
62 | |
63 | static ssize_t |
64 | nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d, |
65 | struct device_attribute *a, char *buf) |
66 | { |
67 | return snprintf(buf, PAGE_SIZE, "%d\n" , 100); |
68 | } |
69 | static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO, |
70 | nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0); |
71 | |
72 | static ssize_t |
73 | nouveau_hwmon_temp1_auto_point1_temp(struct device *d, |
74 | struct device_attribute *a, char *buf) |
75 | { |
76 | struct drm_device *dev = dev_get_drvdata(d); |
77 | struct nouveau_drm *drm = nouveau_drm(dev); |
78 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
79 | |
80 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
81 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST) * 1000); |
82 | } |
83 | static ssize_t |
84 | nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d, |
85 | struct device_attribute *a, |
86 | const char *buf, size_t count) |
87 | { |
88 | struct drm_device *dev = dev_get_drvdata(d); |
89 | struct nouveau_drm *drm = nouveau_drm(dev); |
90 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
91 | long value; |
92 | |
93 | if (kstrtol(buf, 10, &value) == -EINVAL) |
94 | return count; |
95 | |
96 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST, |
97 | value / 1000); |
98 | |
99 | return count; |
100 | } |
101 | static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO | S_IWUSR, |
102 | nouveau_hwmon_temp1_auto_point1_temp, |
103 | nouveau_hwmon_set_temp1_auto_point1_temp, 0); |
104 | |
105 | static ssize_t |
106 | nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d, |
107 | struct device_attribute *a, char *buf) |
108 | { |
109 | struct drm_device *dev = dev_get_drvdata(d); |
110 | struct nouveau_drm *drm = nouveau_drm(dev); |
111 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
112 | |
113 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
114 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000); |
115 | } |
116 | static ssize_t |
117 | nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d, |
118 | struct device_attribute *a, |
119 | const char *buf, size_t count) |
120 | { |
121 | struct drm_device *dev = dev_get_drvdata(d); |
122 | struct nouveau_drm *drm = nouveau_drm(dev); |
123 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
124 | long value; |
125 | |
126 | if (kstrtol(buf, 10, &value) == -EINVAL) |
127 | return count; |
128 | |
129 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST, |
130 | value / 1000); |
131 | |
132 | return count; |
133 | } |
134 | static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, |
135 | nouveau_hwmon_temp1_auto_point1_temp_hyst, |
136 | nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0); |
137 | |
138 | static ssize_t |
139 | nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) |
140 | { |
141 | struct drm_device *dev = dev_get_drvdata(d); |
142 | struct nouveau_drm *drm = nouveau_drm(dev); |
143 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
144 | |
145 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
146 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000); |
147 | } |
148 | static ssize_t |
149 | nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, |
150 | const char *buf, size_t count) |
151 | { |
152 | struct drm_device *dev = dev_get_drvdata(d); |
153 | struct nouveau_drm *drm = nouveau_drm(dev); |
154 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
155 | long value; |
156 | |
157 | if (kstrtol(buf, 10, &value) == -EINVAL) |
158 | return count; |
159 | |
160 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000); |
161 | |
162 | return count; |
163 | } |
164 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp, |
165 | nouveau_hwmon_set_max_temp, |
166 | 0); |
167 | |
168 | static ssize_t |
169 | nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a, |
170 | char *buf) |
171 | { |
172 | struct drm_device *dev = dev_get_drvdata(d); |
173 | struct nouveau_drm *drm = nouveau_drm(dev); |
174 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
175 | |
176 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
177 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000); |
178 | } |
179 | static ssize_t |
180 | nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a, |
181 | const char *buf, size_t count) |
182 | { |
183 | struct drm_device *dev = dev_get_drvdata(d); |
184 | struct nouveau_drm *drm = nouveau_drm(dev); |
185 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
186 | long value; |
187 | |
188 | if (kstrtol(buf, 10, &value) == -EINVAL) |
189 | return count; |
190 | |
191 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST, |
192 | value / 1000); |
193 | |
194 | return count; |
195 | } |
196 | static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, |
197 | nouveau_hwmon_max_temp_hyst, |
198 | nouveau_hwmon_set_max_temp_hyst, 0); |
199 | |
200 | static ssize_t |
201 | nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, |
202 | char *buf) |
203 | { |
204 | struct drm_device *dev = dev_get_drvdata(d); |
205 | struct nouveau_drm *drm = nouveau_drm(dev); |
206 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
207 | |
208 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
209 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000); |
210 | } |
211 | static ssize_t |
212 | nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, |
213 | const char *buf, |
214 | size_t count) |
215 | { |
216 | struct drm_device *dev = dev_get_drvdata(d); |
217 | struct nouveau_drm *drm = nouveau_drm(dev); |
218 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
219 | long value; |
220 | |
221 | if (kstrtol(buf, 10, &value) == -EINVAL) |
222 | return count; |
223 | |
224 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000); |
225 | |
226 | return count; |
227 | } |
228 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, |
229 | nouveau_hwmon_critical_temp, |
230 | nouveau_hwmon_set_critical_temp, |
231 | 0); |
232 | |
233 | static ssize_t |
234 | nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a, |
235 | char *buf) |
236 | { |
237 | struct drm_device *dev = dev_get_drvdata(d); |
238 | struct nouveau_drm *drm = nouveau_drm(dev); |
239 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
240 | |
241 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
242 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000); |
243 | } |
244 | static ssize_t |
245 | nouveau_hwmon_set_critical_temp_hyst(struct device *d, |
246 | struct device_attribute *a, |
247 | const char *buf, |
248 | size_t count) |
249 | { |
250 | struct drm_device *dev = dev_get_drvdata(d); |
251 | struct nouveau_drm *drm = nouveau_drm(dev); |
252 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
253 | long value; |
254 | |
255 | if (kstrtol(buf, 10, &value) == -EINVAL) |
256 | return count; |
257 | |
258 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST, |
259 | value / 1000); |
260 | |
261 | return count; |
262 | } |
263 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, |
264 | nouveau_hwmon_critical_temp_hyst, |
265 | nouveau_hwmon_set_critical_temp_hyst, 0); |
266 | static ssize_t |
267 | nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a, |
268 | char *buf) |
269 | { |
270 | struct drm_device *dev = dev_get_drvdata(d); |
271 | struct nouveau_drm *drm = nouveau_drm(dev); |
272 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
273 | |
274 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
275 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000); |
276 | } |
277 | static ssize_t |
278 | nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a, |
279 | const char *buf, |
280 | size_t count) |
281 | { |
282 | struct drm_device *dev = dev_get_drvdata(d); |
283 | struct nouveau_drm *drm = nouveau_drm(dev); |
284 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
285 | long value; |
286 | |
287 | if (kstrtol(buf, 10, &value) == -EINVAL) |
288 | return count; |
289 | |
290 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN, value / 1000); |
291 | |
292 | return count; |
293 | } |
294 | static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO | S_IWUSR, |
295 | nouveau_hwmon_emergency_temp, |
296 | nouveau_hwmon_set_emergency_temp, |
297 | 0); |
298 | |
299 | static ssize_t |
300 | nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a, |
301 | char *buf) |
302 | { |
303 | struct drm_device *dev = dev_get_drvdata(d); |
304 | struct nouveau_drm *drm = nouveau_drm(dev); |
305 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
306 | |
307 | return snprintf(buf, PAGE_SIZE, "%d\n" , |
308 | therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000); |
309 | } |
310 | static ssize_t |
311 | nouveau_hwmon_set_emergency_temp_hyst(struct device *d, |
312 | struct device_attribute *a, |
313 | const char *buf, |
314 | size_t count) |
315 | { |
316 | struct drm_device *dev = dev_get_drvdata(d); |
317 | struct nouveau_drm *drm = nouveau_drm(dev); |
318 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
319 | long value; |
320 | |
321 | if (kstrtol(buf, 10, &value) == -EINVAL) |
322 | return count; |
323 | |
324 | therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST, |
325 | value / 1000); |
326 | |
327 | return count; |
328 | } |
329 | static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO | S_IWUSR, |
330 | nouveau_hwmon_emergency_temp_hyst, |
331 | nouveau_hwmon_set_emergency_temp_hyst, |
332 | 0); |
333 | |
334 | static ssize_t nouveau_hwmon_show_name(struct device *dev, |
335 | struct device_attribute *attr, |
336 | char *buf) |
337 | { |
338 | return sprintf(buf, "nouveau\n" ); |
339 | } |
340 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0); |
341 | |
342 | static ssize_t nouveau_hwmon_show_update_rate(struct device *dev, |
343 | struct device_attribute *attr, |
344 | char *buf) |
345 | { |
346 | return sprintf(buf, "1000\n" ); |
347 | } |
348 | static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO, |
349 | nouveau_hwmon_show_update_rate, |
350 | NULL, 0); |
351 | |
352 | static ssize_t |
353 | nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr, |
354 | char *buf) |
355 | { |
356 | struct drm_device *dev = dev_get_drvdata(d); |
357 | struct nouveau_drm *drm = nouveau_drm(dev); |
358 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
359 | |
360 | return snprintf(buf, PAGE_SIZE, "%d\n" , therm->fan_sense(therm)); |
361 | } |
362 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input, |
363 | NULL, 0); |
364 | |
365 | static ssize_t |
366 | nouveau_hwmon_get_pwm1_enable(struct device *d, |
367 | struct device_attribute *a, char *buf) |
368 | { |
369 | struct drm_device *dev = dev_get_drvdata(d); |
370 | struct nouveau_drm *drm = nouveau_drm(dev); |
371 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
372 | int ret; |
373 | |
374 | ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE); |
375 | if (ret < 0) |
376 | return ret; |
377 | |
378 | return sprintf(buf, "%i\n" , ret); |
379 | } |
380 | |
381 | static ssize_t |
382 | nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, |
383 | const char *buf, size_t count) |
384 | { |
385 | struct drm_device *dev = dev_get_drvdata(d); |
386 | struct nouveau_drm *drm = nouveau_drm(dev); |
387 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
388 | long value; |
389 | int ret; |
390 | |
391 | ret = kstrtol(buf, 10, &value); |
392 | if (ret) |
393 | return ret; |
394 | |
395 | ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value); |
396 | if (ret) |
397 | return ret; |
398 | else |
399 | return count; |
400 | } |
401 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, |
402 | nouveau_hwmon_get_pwm1_enable, |
403 | nouveau_hwmon_set_pwm1_enable, 0); |
404 | |
405 | static ssize_t |
406 | nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) |
407 | { |
408 | struct drm_device *dev = dev_get_drvdata(d); |
409 | struct nouveau_drm *drm = nouveau_drm(dev); |
410 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
411 | int ret; |
412 | |
413 | ret = therm->fan_get(therm); |
414 | if (ret < 0) |
415 | return ret; |
416 | |
417 | return sprintf(buf, "%i\n" , ret); |
418 | } |
419 | |
420 | static ssize_t |
421 | nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a, |
422 | const char *buf, size_t count) |
423 | { |
424 | struct drm_device *dev = dev_get_drvdata(d); |
425 | struct nouveau_drm *drm = nouveau_drm(dev); |
426 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
427 | int ret = -ENODEV; |
428 | long value; |
429 | |
430 | if (kstrtol(buf, 10, &value) == -EINVAL) |
431 | return -EINVAL; |
432 | |
433 | ret = therm->fan_set(therm, value); |
434 | if (ret) |
435 | return ret; |
436 | |
437 | return count; |
438 | } |
439 | |
440 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, |
441 | nouveau_hwmon_get_pwm1, |
442 | nouveau_hwmon_set_pwm1, 0); |
443 | |
444 | static ssize_t |
445 | nouveau_hwmon_get_pwm1_min(struct device *d, |
446 | struct device_attribute *a, char *buf) |
447 | { |
448 | struct drm_device *dev = dev_get_drvdata(d); |
449 | struct nouveau_drm *drm = nouveau_drm(dev); |
450 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
451 | int ret; |
452 | |
453 | ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY); |
454 | if (ret < 0) |
455 | return ret; |
456 | |
457 | return sprintf(buf, "%i\n" , ret); |
458 | } |
459 | |
460 | static ssize_t |
461 | nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a, |
462 | const char *buf, size_t count) |
463 | { |
464 | struct drm_device *dev = dev_get_drvdata(d); |
465 | struct nouveau_drm *drm = nouveau_drm(dev); |
466 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
467 | long value; |
468 | int ret; |
469 | |
470 | if (kstrtol(buf, 10, &value) == -EINVAL) |
471 | return -EINVAL; |
472 | |
473 | ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value); |
474 | if (ret < 0) |
475 | return ret; |
476 | |
477 | return count; |
478 | } |
479 | |
480 | static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR, |
481 | nouveau_hwmon_get_pwm1_min, |
482 | nouveau_hwmon_set_pwm1_min, 0); |
483 | |
484 | static ssize_t |
485 | nouveau_hwmon_get_pwm1_max(struct device *d, |
486 | struct device_attribute *a, char *buf) |
487 | { |
488 | struct drm_device *dev = dev_get_drvdata(d); |
489 | struct nouveau_drm *drm = nouveau_drm(dev); |
490 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
491 | int ret; |
492 | |
493 | ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY); |
494 | if (ret < 0) |
495 | return ret; |
496 | |
497 | return sprintf(buf, "%i\n" , ret); |
498 | } |
499 | |
500 | static ssize_t |
501 | nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, |
502 | const char *buf, size_t count) |
503 | { |
504 | struct drm_device *dev = dev_get_drvdata(d); |
505 | struct nouveau_drm *drm = nouveau_drm(dev); |
506 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
507 | long value; |
508 | int ret; |
509 | |
510 | if (kstrtol(buf, 10, &value) == -EINVAL) |
511 | return -EINVAL; |
512 | |
513 | ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value); |
514 | if (ret < 0) |
515 | return ret; |
516 | |
517 | return count; |
518 | } |
519 | |
520 | static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, |
521 | nouveau_hwmon_get_pwm1_max, |
522 | nouveau_hwmon_set_pwm1_max, 0); |
523 | |
524 | static struct attribute *hwmon_default_attributes[] = { |
525 | &sensor_dev_attr_name.dev_attr.attr, |
526 | &sensor_dev_attr_update_rate.dev_attr.attr, |
527 | NULL |
528 | }; |
529 | static struct attribute *hwmon_temp_attributes[] = { |
530 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
531 | &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr, |
532 | &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, |
533 | &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr, |
534 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
535 | &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, |
536 | &sensor_dev_attr_temp1_crit.dev_attr.attr, |
537 | &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, |
538 | &sensor_dev_attr_temp1_emergency.dev_attr.attr, |
539 | &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr, |
540 | NULL |
541 | }; |
542 | static struct attribute *hwmon_fan_rpm_attributes[] = { |
543 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
544 | NULL |
545 | }; |
546 | static struct attribute *hwmon_pwm_fan_attributes[] = { |
547 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
548 | &sensor_dev_attr_pwm1.dev_attr.attr, |
549 | &sensor_dev_attr_pwm1_min.dev_attr.attr, |
550 | &sensor_dev_attr_pwm1_max.dev_attr.attr, |
551 | NULL |
552 | }; |
553 | |
554 | static const struct attribute_group hwmon_default_attrgroup = { |
555 | .attrs = hwmon_default_attributes, |
556 | }; |
557 | static const struct attribute_group hwmon_temp_attrgroup = { |
558 | .attrs = hwmon_temp_attributes, |
559 | }; |
560 | static const struct attribute_group hwmon_fan_rpm_attrgroup = { |
561 | .attrs = hwmon_fan_rpm_attributes, |
562 | }; |
563 | static const struct attribute_group hwmon_pwm_fan_attrgroup = { |
564 | .attrs = hwmon_pwm_fan_attributes, |
565 | }; |
566 | #endif |
567 | |
568 | int |
569 | nouveau_hwmon_init(struct drm_device *dev) |
570 | { |
571 | #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) |
572 | struct nouveau_drm *drm = nouveau_drm(dev); |
573 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
574 | struct nouveau_hwmon *hwmon; |
575 | struct device *hwmon_dev; |
576 | int ret = 0; |
577 | |
578 | hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL); |
579 | if (!hwmon) |
580 | return -ENOMEM; |
581 | hwmon->dev = dev; |
582 | |
583 | if (!therm || !therm->temp_get || !therm->attr_get || !therm->attr_set) |
584 | return -ENODEV; |
585 | |
586 | hwmon_dev = hwmon_device_register(&dev->pdev->dev); |
587 | if (IS_ERR(hwmon_dev)) { |
588 | ret = PTR_ERR(hwmon_dev); |
589 | NV_ERROR(drm, "Unable to register hwmon device: %d\n" , ret); |
590 | return ret; |
591 | } |
592 | dev_set_drvdata(hwmon_dev, dev); |
593 | |
594 | /* set the default attributes */ |
595 | ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup); |
596 | if (ret) |
597 | goto error; |
598 | |
599 | /* if the card has a working thermal sensor */ |
600 | if (therm->temp_get(therm) >= 0) { |
601 | ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup); |
602 | if (ret) |
603 | goto error; |
604 | } |
605 | |
606 | /* if the card has a pwm fan */ |
607 | /*XXX: incorrect, need better detection for this, some boards have |
608 | * the gpio entries for pwm fan control even when there's no |
609 | * actual fan connected to it... therm table? */ |
610 | if (therm->fan_get && therm->fan_get(therm) >= 0) { |
611 | ret = sysfs_create_group(&hwmon_dev->kobj, |
612 | &hwmon_pwm_fan_attrgroup); |
613 | if (ret) |
614 | goto error; |
615 | } |
616 | |
617 | /* if the card can read the fan rpm */ |
618 | if (therm->fan_sense(therm) >= 0) { |
619 | ret = sysfs_create_group(&hwmon_dev->kobj, |
620 | &hwmon_fan_rpm_attrgroup); |
621 | if (ret) |
622 | goto error; |
623 | } |
624 | |
625 | hwmon->hwmon = hwmon_dev; |
626 | |
627 | return 0; |
628 | |
629 | error: |
630 | NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n" , ret); |
631 | hwmon_device_unregister(hwmon_dev); |
632 | hwmon->hwmon = NULL; |
633 | return ret; |
634 | #else |
635 | return 0; |
636 | #endif |
637 | } |
638 | |
639 | void |
640 | nouveau_hwmon_fini(struct drm_device *dev) |
641 | { |
642 | #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) |
643 | struct nouveau_hwmon *hwmon = nouveau_hwmon(dev); |
644 | |
645 | if (hwmon->hwmon) { |
646 | sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_default_attrgroup); |
647 | sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_temp_attrgroup); |
648 | sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_pwm_fan_attrgroup); |
649 | sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_fan_rpm_attrgroup); |
650 | |
651 | hwmon_device_unregister(hwmon->hwmon); |
652 | } |
653 | |
654 | nouveau_drm(dev)->hwmon = NULL; |
655 | kfree(hwmon); |
656 | #endif |
657 | } |
658 | |