thermal: use integers rather than strings for thermal values
[linux-2.6] / drivers / thermal / thermal_sys.c
1 /*
2  *  thermal.c - Generic Thermal Management Sysfs support.
3  *
4  *  Copyright (C) 2008 Intel Corp
5  *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
6  *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
7  *
8  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; version 2 of the License.
13  *
14  *  This program is distributed in the hope that it will be useful, but
15  *  WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License along
20  *  with this program; if not, write to the Free Software Foundation, Inc.,
21  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22  *
23  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24  */
25
26 #include <linux/module.h>
27 #include <linux/device.h>
28 #include <linux/err.h>
29 #include <linux/kdev_t.h>
30 #include <linux/idr.h>
31 #include <linux/thermal.h>
32 #include <linux/spinlock.h>
33
34 MODULE_AUTHOR("Zhang Rui");
35 MODULE_DESCRIPTION("Generic thermal management sysfs support");
36 MODULE_LICENSE("GPL");
37
38 #define PREFIX "Thermal: "
39
40 struct thermal_cooling_device_instance {
41         int id;
42         char name[THERMAL_NAME_LENGTH];
43         struct thermal_zone_device *tz;
44         struct thermal_cooling_device *cdev;
45         int trip;
46         char attr_name[THERMAL_NAME_LENGTH];
47         struct device_attribute attr;
48         struct list_head node;
49 };
50
51 static DEFINE_IDR(thermal_tz_idr);
52 static DEFINE_IDR(thermal_cdev_idr);
53 static DEFINE_MUTEX(thermal_idr_lock);
54
55 static LIST_HEAD(thermal_tz_list);
56 static LIST_HEAD(thermal_cdev_list);
57 static DEFINE_MUTEX(thermal_list_lock);
58
59 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
60 {
61         int err;
62
63       again:
64         if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
65                 return -ENOMEM;
66
67         if (lock)
68                 mutex_lock(lock);
69         err = idr_get_new(idr, NULL, id);
70         if (lock)
71                 mutex_unlock(lock);
72         if (unlikely(err == -EAGAIN))
73                 goto again;
74         else if (unlikely(err))
75                 return err;
76
77         *id = *id & MAX_ID_MASK;
78         return 0;
79 }
80
81 static void release_idr(struct idr *idr, struct mutex *lock, int id)
82 {
83         if (lock)
84                 mutex_lock(lock);
85         idr_remove(idr, id);
86         if (lock)
87                 mutex_unlock(lock);
88 }
89
90 /* sys I/F for thermal zone */
91
92 #define to_thermal_zone(_dev) \
93         container_of(_dev, struct thermal_zone_device, device)
94
95 static ssize_t
96 type_show(struct device *dev, struct device_attribute *attr, char *buf)
97 {
98         struct thermal_zone_device *tz = to_thermal_zone(dev);
99
100         return sprintf(buf, "%s\n", tz->type);
101 }
102
103 static ssize_t
104 temp_show(struct device *dev, struct device_attribute *attr, char *buf)
105 {
106         struct thermal_zone_device *tz = to_thermal_zone(dev);
107         long temperature;
108         int ret;
109
110         if (!tz->ops->get_temp)
111                 return -EPERM;
112
113         ret = tz->ops->get_temp(tz, &temperature);
114
115         if (ret)
116                 return ret;
117
118         return sprintf(buf, "%ld\n", temperature);
119 }
120
121 static ssize_t
122 mode_show(struct device *dev, struct device_attribute *attr, char *buf)
123 {
124         struct thermal_zone_device *tz = to_thermal_zone(dev);
125         enum thermal_device_mode mode;
126         int result;
127
128         if (!tz->ops->get_mode)
129                 return -EPERM;
130
131         result = tz->ops->get_mode(tz, &mode);
132         if (result)
133                 return result;
134
135         return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
136                        : "disabled");
137 }
138
139 static ssize_t
140 mode_store(struct device *dev, struct device_attribute *attr,
141            const char *buf, size_t count)
142 {
143         struct thermal_zone_device *tz = to_thermal_zone(dev);
144         int result;
145
146         if (!tz->ops->set_mode)
147                 return -EPERM;
148
149         if (!strncmp(buf, "enabled", sizeof("enabled")))
150                 result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
151         else if (!strncmp(buf, "disabled", sizeof("disabled")))
152                 result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
153         else
154                 result = -EINVAL;
155
156         if (result)
157                 return result;
158
159         return count;
160 }
161
162 static ssize_t
163 trip_point_type_show(struct device *dev, struct device_attribute *attr,
164                      char *buf)
165 {
166         struct thermal_zone_device *tz = to_thermal_zone(dev);
167         enum thermal_trip_type type;
168         int trip, result;
169
170         if (!tz->ops->get_trip_type)
171                 return -EPERM;
172
173         if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
174                 return -EINVAL;
175
176         result = tz->ops->get_trip_type(tz, trip, &type);
177         if (result)
178                 return result;
179
180         switch (type) {
181         case THERMAL_TRIP_CRITICAL:
182                 return sprintf(buf, "critical");
183         case THERMAL_TRIP_HOT:
184                 return sprintf(buf, "hot");
185         case THERMAL_TRIP_PASSIVE:
186                 return sprintf(buf, "passive");
187         case THERMAL_TRIP_ACTIVE:
188                 return sprintf(buf, "active");
189         default:
190                 return sprintf(buf, "unknown");
191         }
192 }
193
194 static ssize_t
195 trip_point_temp_show(struct device *dev, struct device_attribute *attr,
196                      char *buf)
197 {
198         struct thermal_zone_device *tz = to_thermal_zone(dev);
199         int trip, ret;
200         long temperature;
201
202         if (!tz->ops->get_trip_temp)
203                 return -EPERM;
204
205         if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
206                 return -EINVAL;
207
208         ret = tz->ops->get_trip_temp(tz, trip, &temperature);
209
210         if (ret)
211                 return ret;
212
213         return sprintf(buf, "%ld\n", temperature);
214 }
215
216 static DEVICE_ATTR(type, 0444, type_show, NULL);
217 static DEVICE_ATTR(temp, 0444, temp_show, NULL);
218 static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
219
220 static struct device_attribute trip_point_attrs[] = {
221         __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
222         __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
223         __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
224         __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
225         __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
226         __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
227         __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
228         __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
229         __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
230         __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
231         __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
232         __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
233         __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
234         __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
235         __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
236         __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
237         __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
238         __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
239         __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
240         __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
241         __ATTR(trip_point_10_type, 0444, trip_point_type_show, NULL),
242         __ATTR(trip_point_10_temp, 0444, trip_point_temp_show, NULL),
243         __ATTR(trip_point_11_type, 0444, trip_point_type_show, NULL),
244         __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL),
245 };
246
247 #define TRIP_POINT_ATTR_ADD(_dev, _index, result)     \
248 do {    \
249         result = device_create_file(_dev,       \
250                                 &trip_point_attrs[_index * 2]); \
251         if (result)     \
252                 break;  \
253         result = device_create_file(_dev,       \
254                         &trip_point_attrs[_index * 2 + 1]);     \
255 } while (0)
256
257 #define TRIP_POINT_ATTR_REMOVE(_dev, _index)    \
258 do {    \
259         device_remove_file(_dev, &trip_point_attrs[_index * 2]);        \
260         device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]);    \
261 } while (0)
262
263 /* sys I/F for cooling device */
264 #define to_cooling_device(_dev) \
265         container_of(_dev, struct thermal_cooling_device, device)
266
267 static ssize_t
268 thermal_cooling_device_type_show(struct device *dev,
269                                  struct device_attribute *attr, char *buf)
270 {
271         struct thermal_cooling_device *cdev = to_cooling_device(dev);
272
273         return sprintf(buf, "%s\n", cdev->type);
274 }
275
276 static ssize_t
277 thermal_cooling_device_max_state_show(struct device *dev,
278                                       struct device_attribute *attr, char *buf)
279 {
280         struct thermal_cooling_device *cdev = to_cooling_device(dev);
281         unsigned long state;
282         int ret;
283
284         ret = cdev->ops->get_max_state(cdev, &state);
285         if (ret)
286                 return ret;
287         return sprintf(buf, "%ld\n", state);
288 }
289
290 static ssize_t
291 thermal_cooling_device_cur_state_show(struct device *dev,
292                                       struct device_attribute *attr, char *buf)
293 {
294         struct thermal_cooling_device *cdev = to_cooling_device(dev);
295         unsigned long state;
296         int ret;
297
298         ret = cdev->ops->get_cur_state(cdev, &state);
299         if (ret)
300                 return ret;
301         return sprintf(buf, "%ld\n", state);
302 }
303
304 static ssize_t
305 thermal_cooling_device_cur_state_store(struct device *dev,
306                                        struct device_attribute *attr,
307                                        const char *buf, size_t count)
308 {
309         struct thermal_cooling_device *cdev = to_cooling_device(dev);
310         unsigned long state;
311         int result;
312
313         if (!sscanf(buf, "%ld\n", &state))
314                 return -EINVAL;
315
316         if (state < 0)
317                 return -EINVAL;
318
319         result = cdev->ops->set_cur_state(cdev, state);
320         if (result)
321                 return result;
322         return count;
323 }
324
325 static struct device_attribute dev_attr_cdev_type =
326 __ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
327 static DEVICE_ATTR(max_state, 0444,
328                    thermal_cooling_device_max_state_show, NULL);
329 static DEVICE_ATTR(cur_state, 0644,
330                    thermal_cooling_device_cur_state_show,
331                    thermal_cooling_device_cur_state_store);
332
333 static ssize_t
334 thermal_cooling_device_trip_point_show(struct device *dev,
335                                        struct device_attribute *attr, char *buf)
336 {
337         struct thermal_cooling_device_instance *instance;
338
339         instance =
340             container_of(attr, struct thermal_cooling_device_instance, attr);
341
342         if (instance->trip == THERMAL_TRIPS_NONE)
343                 return sprintf(buf, "-1\n");
344         else
345                 return sprintf(buf, "%d\n", instance->trip);
346 }
347
348 /* Device management */
349
350 #if defined(CONFIG_THERMAL_HWMON)
351
352 /* hwmon sys I/F */
353 #include <linux/hwmon.h>
354 static LIST_HEAD(thermal_hwmon_list);
355
356 static ssize_t
357 name_show(struct device *dev, struct device_attribute *attr, char *buf)
358 {
359         struct thermal_hwmon_device *hwmon = dev->driver_data;
360         return sprintf(buf, "%s\n", hwmon->type);
361 }
362 static DEVICE_ATTR(name, 0444, name_show, NULL);
363
364 static ssize_t
365 temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
366 {
367         long temperature;
368         int ret;
369         struct thermal_hwmon_attr *hwmon_attr
370                         = container_of(attr, struct thermal_hwmon_attr, attr);
371         struct thermal_zone_device *tz
372                         = container_of(hwmon_attr, struct thermal_zone_device,
373                                        temp_input);
374
375         ret = tz->ops->get_temp(tz, &temperature);
376
377         if (ret)
378                 return ret;
379
380         return sprintf(buf, "%ld\n", temperature);
381 }
382
383 static ssize_t
384 temp_crit_show(struct device *dev, struct device_attribute *attr,
385                 char *buf)
386 {
387         struct thermal_hwmon_attr *hwmon_attr
388                         = container_of(attr, struct thermal_hwmon_attr, attr);
389         struct thermal_zone_device *tz
390                         = container_of(hwmon_attr, struct thermal_zone_device,
391                                        temp_crit);
392         long temperature;
393         int ret;
394
395         ret = tz->ops->get_trip_temp(tz, 0, &temperature);
396         if (ret)
397                 return ret;
398
399         return sprintf(buf, "%ld\n", temperature);
400 }
401
402
403 static int
404 thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
405 {
406         struct thermal_hwmon_device *hwmon;
407         int new_hwmon_device = 1;
408         int result;
409
410         mutex_lock(&thermal_list_lock);
411         list_for_each_entry(hwmon, &thermal_hwmon_list, node)
412                 if (!strcmp(hwmon->type, tz->type)) {
413                         new_hwmon_device = 0;
414                         mutex_unlock(&thermal_list_lock);
415                         goto register_sys_interface;
416                 }
417         mutex_unlock(&thermal_list_lock);
418
419         hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
420         if (!hwmon)
421                 return -ENOMEM;
422
423         INIT_LIST_HEAD(&hwmon->tz_list);
424         strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
425         hwmon->device = hwmon_device_register(NULL);
426         if (IS_ERR(hwmon->device)) {
427                 result = PTR_ERR(hwmon->device);
428                 goto free_mem;
429         }
430         hwmon->device->driver_data = hwmon;
431         result = device_create_file(hwmon->device, &dev_attr_name);
432         if (result)
433                 goto unregister_hwmon_device;
434
435  register_sys_interface:
436         tz->hwmon = hwmon;
437         hwmon->count++;
438
439         snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
440                  "temp%d_input", hwmon->count);
441         tz->temp_input.attr.attr.name = tz->temp_input.name;
442         tz->temp_input.attr.attr.mode = 0444;
443         tz->temp_input.attr.show = temp_input_show;
444         result = device_create_file(hwmon->device, &tz->temp_input.attr);
445         if (result)
446                 goto unregister_hwmon_device;
447
448         if (tz->ops->get_crit_temp) {
449                 unsigned long temperature;
450                 if (!tz->ops->get_crit_temp(tz, &temperature)) {
451                         snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
452                                 "temp%d_crit", hwmon->count);
453                         tz->temp_crit.attr.attr.name = tz->temp_crit.name;
454                         tz->temp_crit.attr.attr.mode = 0444;
455                         tz->temp_crit.attr.show = temp_crit_show;
456                         result = device_create_file(hwmon->device,
457                                                     &tz->temp_crit.attr);
458                         if (result)
459                                 goto unregister_hwmon_device;
460                 }
461         }
462
463         mutex_lock(&thermal_list_lock);
464         if (new_hwmon_device)
465                 list_add_tail(&hwmon->node, &thermal_hwmon_list);
466         list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
467         mutex_unlock(&thermal_list_lock);
468
469         return 0;
470
471  unregister_hwmon_device:
472         device_remove_file(hwmon->device, &tz->temp_crit.attr);
473         device_remove_file(hwmon->device, &tz->temp_input.attr);
474         if (new_hwmon_device) {
475                 device_remove_file(hwmon->device, &dev_attr_name);
476                 hwmon_device_unregister(hwmon->device);
477         }
478  free_mem:
479         if (new_hwmon_device)
480                 kfree(hwmon);
481
482         return result;
483 }
484
485 static void
486 thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
487 {
488         struct thermal_hwmon_device *hwmon = tz->hwmon;
489
490         tz->hwmon = NULL;
491         device_remove_file(hwmon->device, &tz->temp_input.attr);
492         device_remove_file(hwmon->device, &tz->temp_crit.attr);
493
494         mutex_lock(&thermal_list_lock);
495         list_del(&tz->hwmon_node);
496         if (!list_empty(&hwmon->tz_list)) {
497                 mutex_unlock(&thermal_list_lock);
498                 return;
499         }
500         list_del(&hwmon->node);
501         mutex_unlock(&thermal_list_lock);
502
503         device_remove_file(hwmon->device, &dev_attr_name);
504         hwmon_device_unregister(hwmon->device);
505         kfree(hwmon);
506 }
507 #else
508 static int
509 thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
510 {
511         return 0;
512 }
513
514 static void
515 thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
516 {
517 }
518 #endif
519
520
521 /**
522  * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
523  * @tz:         thermal zone device
524  * @trip:       indicates which trip point the cooling devices is
525  *              associated with in this thermal zone.
526  * @cdev:       thermal cooling device
527  *
528  * This function is usually called in the thermal zone device .bind callback.
529  */
530 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
531                                      int trip,
532                                      struct thermal_cooling_device *cdev)
533 {
534         struct thermal_cooling_device_instance *dev;
535         struct thermal_cooling_device_instance *pos;
536         struct thermal_zone_device *pos1;
537         struct thermal_cooling_device *pos2;
538         int result;
539
540         if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
541                 return -EINVAL;
542
543         list_for_each_entry(pos1, &thermal_tz_list, node) {
544                 if (pos1 == tz)
545                         break;
546         }
547         list_for_each_entry(pos2, &thermal_cdev_list, node) {
548                 if (pos2 == cdev)
549                         break;
550         }
551
552         if (tz != pos1 || cdev != pos2)
553                 return -EINVAL;
554
555         dev =
556             kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
557         if (!dev)
558                 return -ENOMEM;
559         dev->tz = tz;
560         dev->cdev = cdev;
561         dev->trip = trip;
562         result = get_idr(&tz->idr, &tz->lock, &dev->id);
563         if (result)
564                 goto free_mem;
565
566         sprintf(dev->name, "cdev%d", dev->id);
567         result =
568             sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
569         if (result)
570                 goto release_idr;
571
572         sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
573         dev->attr.attr.name = dev->attr_name;
574         dev->attr.attr.mode = 0444;
575         dev->attr.show = thermal_cooling_device_trip_point_show;
576         result = device_create_file(&tz->device, &dev->attr);
577         if (result)
578                 goto remove_symbol_link;
579
580         mutex_lock(&tz->lock);
581         list_for_each_entry(pos, &tz->cooling_devices, node)
582             if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
583                 result = -EEXIST;
584                 break;
585         }
586         if (!result)
587                 list_add_tail(&dev->node, &tz->cooling_devices);
588         mutex_unlock(&tz->lock);
589
590         if (!result)
591                 return 0;
592
593         device_remove_file(&tz->device, &dev->attr);
594       remove_symbol_link:
595         sysfs_remove_link(&tz->device.kobj, dev->name);
596       release_idr:
597         release_idr(&tz->idr, &tz->lock, dev->id);
598       free_mem:
599         kfree(dev);
600         return result;
601 }
602
603 EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
604
605 /**
606  * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
607  * @tz:         thermal zone device
608  * @trip:       indicates which trip point the cooling devices is
609  *              associated with in this thermal zone.
610  * @cdev:       thermal cooling device
611  *
612  * This function is usually called in the thermal zone device .unbind callback.
613  */
614 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
615                                        int trip,
616                                        struct thermal_cooling_device *cdev)
617 {
618         struct thermal_cooling_device_instance *pos, *next;
619
620         mutex_lock(&tz->lock);
621         list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
622                 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
623                         list_del(&pos->node);
624                         mutex_unlock(&tz->lock);
625                         goto unbind;
626                 }
627         }
628         mutex_unlock(&tz->lock);
629
630         return -ENODEV;
631
632       unbind:
633         device_remove_file(&tz->device, &pos->attr);
634         sysfs_remove_link(&tz->device.kobj, pos->name);
635         release_idr(&tz->idr, &tz->lock, pos->id);
636         kfree(pos);
637         return 0;
638 }
639
640 EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
641
642 static void thermal_release(struct device *dev)
643 {
644         struct thermal_zone_device *tz;
645         struct thermal_cooling_device *cdev;
646
647         if (!strncmp(dev_name(dev), "thermal_zone", sizeof "thermal_zone" - 1)) {
648                 tz = to_thermal_zone(dev);
649                 kfree(tz);
650         } else {
651                 cdev = to_cooling_device(dev);
652                 kfree(cdev);
653         }
654 }
655
656 static struct class thermal_class = {
657         .name = "thermal",
658         .dev_release = thermal_release,
659 };
660
661 /**
662  * thermal_cooling_device_register - register a new thermal cooling device
663  * @type:       the thermal cooling device type.
664  * @devdata:    device private data.
665  * @ops:                standard thermal cooling devices callbacks.
666  */
667 struct thermal_cooling_device *thermal_cooling_device_register(char *type,
668                                                                void *devdata,
669                                                                struct
670                                                                thermal_cooling_device_ops
671                                                                *ops)
672 {
673         struct thermal_cooling_device *cdev;
674         struct thermal_zone_device *pos;
675         int result;
676
677         if (strlen(type) >= THERMAL_NAME_LENGTH)
678                 return ERR_PTR(-EINVAL);
679
680         if (!ops || !ops->get_max_state || !ops->get_cur_state ||
681             !ops->set_cur_state)
682                 return ERR_PTR(-EINVAL);
683
684         cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
685         if (!cdev)
686                 return ERR_PTR(-ENOMEM);
687
688         result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
689         if (result) {
690                 kfree(cdev);
691                 return ERR_PTR(result);
692         }
693
694         strcpy(cdev->type, type);
695         cdev->ops = ops;
696         cdev->device.class = &thermal_class;
697         cdev->devdata = devdata;
698         dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
699         result = device_register(&cdev->device);
700         if (result) {
701                 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
702                 kfree(cdev);
703                 return ERR_PTR(result);
704         }
705
706         /* sys I/F */
707         if (type) {
708                 result = device_create_file(&cdev->device, &dev_attr_cdev_type);
709                 if (result)
710                         goto unregister;
711         }
712
713         result = device_create_file(&cdev->device, &dev_attr_max_state);
714         if (result)
715                 goto unregister;
716
717         result = device_create_file(&cdev->device, &dev_attr_cur_state);
718         if (result)
719                 goto unregister;
720
721         mutex_lock(&thermal_list_lock);
722         list_add(&cdev->node, &thermal_cdev_list);
723         list_for_each_entry(pos, &thermal_tz_list, node) {
724                 if (!pos->ops->bind)
725                         continue;
726                 result = pos->ops->bind(pos, cdev);
727                 if (result)
728                         break;
729
730         }
731         mutex_unlock(&thermal_list_lock);
732
733         if (!result)
734                 return cdev;
735
736       unregister:
737         release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
738         device_unregister(&cdev->device);
739         return ERR_PTR(result);
740 }
741
742 EXPORT_SYMBOL(thermal_cooling_device_register);
743
744 /**
745  * thermal_cooling_device_unregister - removes the registered thermal cooling device
746  * @cdev:       the thermal cooling device to remove.
747  *
748  * thermal_cooling_device_unregister() must be called when the device is no
749  * longer needed.
750  */
751 void thermal_cooling_device_unregister(struct
752                                        thermal_cooling_device
753                                        *cdev)
754 {
755         struct thermal_zone_device *tz;
756         struct thermal_cooling_device *pos = NULL;
757
758         if (!cdev)
759                 return;
760
761         mutex_lock(&thermal_list_lock);
762         list_for_each_entry(pos, &thermal_cdev_list, node)
763             if (pos == cdev)
764                 break;
765         if (pos != cdev) {
766                 /* thermal cooling device not found */
767                 mutex_unlock(&thermal_list_lock);
768                 return;
769         }
770         list_del(&cdev->node);
771         list_for_each_entry(tz, &thermal_tz_list, node) {
772                 if (!tz->ops->unbind)
773                         continue;
774                 tz->ops->unbind(tz, cdev);
775         }
776         mutex_unlock(&thermal_list_lock);
777         if (cdev->type[0])
778                 device_remove_file(&cdev->device, &dev_attr_cdev_type);
779         device_remove_file(&cdev->device, &dev_attr_max_state);
780         device_remove_file(&cdev->device, &dev_attr_cur_state);
781
782         release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
783         device_unregister(&cdev->device);
784         return;
785 }
786
787 EXPORT_SYMBOL(thermal_cooling_device_unregister);
788
789 /**
790  * thermal_zone_device_register - register a new thermal zone device
791  * @type:       the thermal zone device type
792  * @trips:      the number of trip points the thermal zone support
793  * @devdata:    private device data
794  * @ops:        standard thermal zone device callbacks
795  *
796  * thermal_zone_device_unregister() must be called when the device is no
797  * longer needed.
798  */
799 struct thermal_zone_device *thermal_zone_device_register(char *type,
800                                                          int trips,
801                                                          void *devdata, struct
802                                                          thermal_zone_device_ops
803                                                          *ops)
804 {
805         struct thermal_zone_device *tz;
806         struct thermal_cooling_device *pos;
807         int result;
808         int count;
809
810         if (strlen(type) >= THERMAL_NAME_LENGTH)
811                 return ERR_PTR(-EINVAL);
812
813         if (trips > THERMAL_MAX_TRIPS || trips < 0)
814                 return ERR_PTR(-EINVAL);
815
816         if (!ops || !ops->get_temp)
817                 return ERR_PTR(-EINVAL);
818
819         tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
820         if (!tz)
821                 return ERR_PTR(-ENOMEM);
822
823         INIT_LIST_HEAD(&tz->cooling_devices);
824         idr_init(&tz->idr);
825         mutex_init(&tz->lock);
826         result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
827         if (result) {
828                 kfree(tz);
829                 return ERR_PTR(result);
830         }
831
832         strcpy(tz->type, type);
833         tz->ops = ops;
834         tz->device.class = &thermal_class;
835         tz->devdata = devdata;
836         tz->trips = trips;
837         dev_set_name(&tz->device, "thermal_zone%d", tz->id);
838         result = device_register(&tz->device);
839         if (result) {
840                 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
841                 kfree(tz);
842                 return ERR_PTR(result);
843         }
844
845         /* sys I/F */
846         if (type) {
847                 result = device_create_file(&tz->device, &dev_attr_type);
848                 if (result)
849                         goto unregister;
850         }
851
852         result = device_create_file(&tz->device, &dev_attr_temp);
853         if (result)
854                 goto unregister;
855
856         if (ops->get_mode) {
857                 result = device_create_file(&tz->device, &dev_attr_mode);
858                 if (result)
859                         goto unregister;
860         }
861
862         for (count = 0; count < trips; count++) {
863                 TRIP_POINT_ATTR_ADD(&tz->device, count, result);
864                 if (result)
865                         goto unregister;
866         }
867
868         result = thermal_add_hwmon_sysfs(tz);
869         if (result)
870                 goto unregister;
871
872         mutex_lock(&thermal_list_lock);
873         list_add_tail(&tz->node, &thermal_tz_list);
874         if (ops->bind)
875                 list_for_each_entry(pos, &thermal_cdev_list, node) {
876                 result = ops->bind(tz, pos);
877                 if (result)
878                         break;
879                 }
880         mutex_unlock(&thermal_list_lock);
881
882         if (!result)
883                 return tz;
884
885       unregister:
886         release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
887         device_unregister(&tz->device);
888         return ERR_PTR(result);
889 }
890
891 EXPORT_SYMBOL(thermal_zone_device_register);
892
893 /**
894  * thermal_device_unregister - removes the registered thermal zone device
895  * @tz: the thermal zone device to remove
896  */
897 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
898 {
899         struct thermal_cooling_device *cdev;
900         struct thermal_zone_device *pos = NULL;
901         int count;
902
903         if (!tz)
904                 return;
905
906         mutex_lock(&thermal_list_lock);
907         list_for_each_entry(pos, &thermal_tz_list, node)
908             if (pos == tz)
909                 break;
910         if (pos != tz) {
911                 /* thermal zone device not found */
912                 mutex_unlock(&thermal_list_lock);
913                 return;
914         }
915         list_del(&tz->node);
916         if (tz->ops->unbind)
917                 list_for_each_entry(cdev, &thermal_cdev_list, node)
918                     tz->ops->unbind(tz, cdev);
919         mutex_unlock(&thermal_list_lock);
920
921         if (tz->type[0])
922                 device_remove_file(&tz->device, &dev_attr_type);
923         device_remove_file(&tz->device, &dev_attr_temp);
924         if (tz->ops->get_mode)
925                 device_remove_file(&tz->device, &dev_attr_mode);
926
927         for (count = 0; count < tz->trips; count++)
928                 TRIP_POINT_ATTR_REMOVE(&tz->device, count);
929
930         thermal_remove_hwmon_sysfs(tz);
931         release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
932         idr_destroy(&tz->idr);
933         mutex_destroy(&tz->lock);
934         device_unregister(&tz->device);
935         return;
936 }
937
938 EXPORT_SYMBOL(thermal_zone_device_unregister);
939
940 static int __init thermal_init(void)
941 {
942         int result = 0;
943
944         result = class_register(&thermal_class);
945         if (result) {
946                 idr_destroy(&thermal_tz_idr);
947                 idr_destroy(&thermal_cdev_idr);
948                 mutex_destroy(&thermal_idr_lock);
949                 mutex_destroy(&thermal_list_lock);
950         }
951         return result;
952 }
953
954 static void __exit thermal_exit(void)
955 {
956         class_unregister(&thermal_class);
957         idr_destroy(&thermal_tz_idr);
958         idr_destroy(&thermal_cdev_idr);
959         mutex_destroy(&thermal_idr_lock);
960         mutex_destroy(&thermal_list_lock);
961 }
962
963 subsys_initcall(thermal_init);
964 module_exit(thermal_exit);