]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/thermal/thermal.c
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx
[linux-2.6-omap-h63xx.git] / drivers / thermal / thermal.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 #include <linux/hwmon.h>
34 #include <linux/hwmon-sysfs.h>
35
36 MODULE_AUTHOR("Zhang Rui");
37 MODULE_DESCRIPTION("Generic thermal management sysfs support");
38 MODULE_LICENSE("GPL");
39
40 #define PREFIX "Thermal: "
41
42 struct thermal_cooling_device_instance {
43         int id;
44         char name[THERMAL_NAME_LENGTH];
45         struct thermal_zone_device *tz;
46         struct thermal_cooling_device *cdev;
47         int trip;
48         char attr_name[THERMAL_NAME_LENGTH];
49         struct device_attribute attr;
50         struct list_head node;
51 };
52
53 static DEFINE_IDR(thermal_tz_idr);
54 static DEFINE_IDR(thermal_cdev_idr);
55 static DEFINE_MUTEX(thermal_idr_lock);
56
57 static LIST_HEAD(thermal_tz_list);
58 static LIST_HEAD(thermal_cdev_list);
59 static DEFINE_MUTEX(thermal_list_lock);
60
61 static struct device *thermal_hwmon;
62 #define MAX_THERMAL_ZONES       10
63
64 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
65 {
66         int err;
67
68       again:
69         if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
70                 return -ENOMEM;
71
72         if (lock)
73                 mutex_lock(lock);
74         err = idr_get_new(idr, NULL, id);
75         if (lock)
76                 mutex_unlock(lock);
77         if (unlikely(err == -EAGAIN))
78                 goto again;
79         else if (unlikely(err))
80                 return err;
81
82         *id = *id & MAX_ID_MASK;
83         return 0;
84 }
85
86 static void release_idr(struct idr *idr, struct mutex *lock, int id)
87 {
88         if (lock)
89                 mutex_lock(lock);
90         idr_remove(idr, id);
91         if (lock)
92                 mutex_unlock(lock);
93 }
94
95 /* hwmon sys I/F*/
96 static ssize_t
97 name_show(struct device *dev, struct device_attribute *attr, char *buf)
98 {
99         return sprintf(buf, "thermal_sys_class\n");
100 }
101
102 static ssize_t
103 temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
104 {
105         struct thermal_zone_device *tz;
106         struct sensor_device_attribute *sensor_attr
107                                                 = to_sensor_dev_attr(attr);
108
109         list_for_each_entry(tz, &thermal_tz_list, node)
110                 if (tz->id == sensor_attr->index)
111                         return tz->ops->get_temp(tz, buf);
112
113         return -ENODEV;
114 }
115
116 static ssize_t
117 temp_crit_show(struct device *dev, struct device_attribute *attr,
118                 char *buf)
119 {
120         struct thermal_zone_device *tz;
121         struct sensor_device_attribute *sensor_attr
122                                                 = to_sensor_dev_attr(attr);
123
124         list_for_each_entry(tz, &thermal_tz_list, node)
125                 if (tz->id == sensor_attr->index)
126                         return tz->ops->get_trip_temp(tz, 0, buf);
127
128         return -ENODEV;
129 }
130
131 static DEVICE_ATTR(name, 0444, name_show, NULL);
132 static struct sensor_device_attribute sensor_attrs[] = {
133         SENSOR_ATTR(temp1_input, 0444, temp_input_show, NULL, 0),
134         SENSOR_ATTR(temp1_crit, 0444, temp_crit_show, NULL, 0),
135         SENSOR_ATTR(temp2_input, 0444, temp_input_show, NULL, 1),
136         SENSOR_ATTR(temp2_crit, 0444, temp_crit_show, NULL, 1),
137         SENSOR_ATTR(temp3_input, 0444, temp_input_show, NULL, 2),
138         SENSOR_ATTR(temp3_crit, 0444, temp_crit_show, NULL, 2),
139         SENSOR_ATTR(temp4_input, 0444, temp_input_show, NULL, 3),
140         SENSOR_ATTR(temp4_crit, 0444, temp_crit_show, NULL, 3),
141         SENSOR_ATTR(temp5_input, 0444, temp_input_show, NULL, 4),
142         SENSOR_ATTR(temp5_crit, 0444, temp_crit_show, NULL, 4),
143         SENSOR_ATTR(temp6_input, 0444, temp_input_show, NULL, 5),
144         SENSOR_ATTR(temp6_crit, 0444, temp_crit_show, NULL, 5),
145         SENSOR_ATTR(temp7_input, 0444, temp_input_show, NULL, 6),
146         SENSOR_ATTR(temp7_crit, 0444, temp_crit_show, NULL, 6),
147         SENSOR_ATTR(temp8_input, 0444, temp_input_show, NULL, 7),
148         SENSOR_ATTR(temp8_crit, 0444, temp_crit_show, NULL, 7),
149         SENSOR_ATTR(temp9_input, 0444, temp_input_show, NULL, 8),
150         SENSOR_ATTR(temp9_crit, 0444, temp_crit_show, NULL, 8),
151         SENSOR_ATTR(temp10_input, 0444, temp_input_show, NULL, 9),
152         SENSOR_ATTR(temp10_crit, 0444, temp_crit_show, NULL, 9),
153 };
154
155 /* thermal zone sys I/F */
156
157 #define to_thermal_zone(_dev) \
158         container_of(_dev, struct thermal_zone_device, device)
159
160 static ssize_t
161 type_show(struct device *dev, struct device_attribute *attr, char *buf)
162 {
163         struct thermal_zone_device *tz = to_thermal_zone(dev);
164
165         return sprintf(buf, "%s\n", tz->type);
166 }
167
168 static ssize_t
169 temp_show(struct device *dev, struct device_attribute *attr, char *buf)
170 {
171         struct thermal_zone_device *tz = to_thermal_zone(dev);
172
173         if (!tz->ops->get_temp)
174                 return -EPERM;
175
176         return tz->ops->get_temp(tz, buf);
177 }
178
179 static ssize_t
180 mode_show(struct device *dev, struct device_attribute *attr, char *buf)
181 {
182         struct thermal_zone_device *tz = to_thermal_zone(dev);
183
184         if (!tz->ops->get_mode)
185                 return -EPERM;
186
187         return tz->ops->get_mode(tz, buf);
188 }
189
190 static ssize_t
191 mode_store(struct device *dev, struct device_attribute *attr,
192            const char *buf, size_t count)
193 {
194         struct thermal_zone_device *tz = to_thermal_zone(dev);
195         int result;
196
197         if (!tz->ops->set_mode)
198                 return -EPERM;
199
200         result = tz->ops->set_mode(tz, buf);
201         if (result)
202                 return result;
203
204         return count;
205 }
206
207 static ssize_t
208 trip_point_type_show(struct device *dev, struct device_attribute *attr,
209                      char *buf)
210 {
211         struct thermal_zone_device *tz = to_thermal_zone(dev);
212         int trip;
213
214         if (!tz->ops->get_trip_type)
215                 return -EPERM;
216
217         if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
218                 return -EINVAL;
219
220         return tz->ops->get_trip_type(tz, trip, buf);
221 }
222
223 static ssize_t
224 trip_point_temp_show(struct device *dev, struct device_attribute *attr,
225                      char *buf)
226 {
227         struct thermal_zone_device *tz = to_thermal_zone(dev);
228         int trip;
229
230         if (!tz->ops->get_trip_temp)
231                 return -EPERM;
232
233         if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
234                 return -EINVAL;
235
236         return tz->ops->get_trip_temp(tz, trip, buf);
237 }
238
239 static DEVICE_ATTR(type, 0444, type_show, NULL);
240 static DEVICE_ATTR(temp, 0444, temp_show, NULL);
241 static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
242
243 static struct device_attribute trip_point_attrs[] = {
244         __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
245         __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
246         __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
247         __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
248         __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
249         __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
250         __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
251         __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
252         __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
253         __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
254         __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
255         __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
256         __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
257         __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
258         __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
259         __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
260         __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
261         __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
262         __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
263         __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
264 };
265
266 #define TRIP_POINT_ATTR_ADD(_dev, _index, result)     \
267 do {    \
268         result = device_create_file(_dev,       \
269                                 &trip_point_attrs[_index * 2]); \
270         if (result)     \
271                 break;  \
272         result = device_create_file(_dev,       \
273                         &trip_point_attrs[_index * 2 + 1]);     \
274 } while (0)
275
276 #define TRIP_POINT_ATTR_REMOVE(_dev, _index)    \
277 do {    \
278         device_remove_file(_dev, &trip_point_attrs[_index * 2]);        \
279         device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]);    \
280 } while (0)
281
282 /* cooling device sys I/F */
283 #define to_cooling_device(_dev) \
284         container_of(_dev, struct thermal_cooling_device, device)
285
286 static ssize_t
287 thermal_cooling_device_type_show(struct device *dev,
288                                  struct device_attribute *attr, char *buf)
289 {
290         struct thermal_cooling_device *cdev = to_cooling_device(dev);
291
292         return sprintf(buf, "%s\n", cdev->type);
293 }
294
295 static ssize_t
296 thermal_cooling_device_max_state_show(struct device *dev,
297                                       struct device_attribute *attr, char *buf)
298 {
299         struct thermal_cooling_device *cdev = to_cooling_device(dev);
300
301         return cdev->ops->get_max_state(cdev, buf);
302 }
303
304 static ssize_t
305 thermal_cooling_device_cur_state_show(struct device *dev,
306                                       struct device_attribute *attr, char *buf)
307 {
308         struct thermal_cooling_device *cdev = to_cooling_device(dev);
309
310         return cdev->ops->get_cur_state(cdev, buf);
311 }
312
313 static ssize_t
314 thermal_cooling_device_cur_state_store(struct device *dev,
315                                        struct device_attribute *attr,
316                                        const char *buf, size_t count)
317 {
318         struct thermal_cooling_device *cdev = to_cooling_device(dev);
319         int state;
320         int result;
321
322         if (!sscanf(buf, "%d\n", &state))
323                 return -EINVAL;
324
325         if (state < 0)
326                 return -EINVAL;
327
328         result = cdev->ops->set_cur_state(cdev, state);
329         if (result)
330                 return result;
331         return count;
332 }
333
334 static struct device_attribute dev_attr_cdev_type =
335 __ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
336 static DEVICE_ATTR(max_state, 0444,
337                    thermal_cooling_device_max_state_show, NULL);
338 static DEVICE_ATTR(cur_state, 0644,
339                    thermal_cooling_device_cur_state_show,
340                    thermal_cooling_device_cur_state_store);
341
342 static ssize_t
343 thermal_cooling_device_trip_point_show(struct device *dev,
344                                        struct device_attribute *attr, char *buf)
345 {
346         struct thermal_cooling_device_instance *instance;
347
348         instance =
349             container_of(attr, struct thermal_cooling_device_instance, attr);
350
351         if (instance->trip == THERMAL_TRIPS_NONE)
352                 return sprintf(buf, "-1\n");
353         else
354                 return sprintf(buf, "%d\n", instance->trip);
355 }
356
357 /* Device management */
358
359 /**
360  * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
361  * @tz:         thermal zone device
362  * @trip:       indicates which trip point the cooling devices is
363  *              associated with in this thermal zone.
364  * @cdev:       thermal cooling device
365  *
366  * This function is usually called in the thermal zone device .bind callback.
367  */
368 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
369                                      int trip,
370                                      struct thermal_cooling_device *cdev)
371 {
372         struct thermal_cooling_device_instance *dev;
373         struct thermal_cooling_device_instance *pos;
374         struct thermal_zone_device *pos1;
375         struct thermal_cooling_device *pos2;
376         int result;
377
378         if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
379                 return -EINVAL;
380
381         list_for_each_entry(pos1, &thermal_tz_list, node) {
382                 if (pos1 == tz)
383                         break;
384         }
385         list_for_each_entry(pos2, &thermal_cdev_list, node) {
386                 if (pos2 == cdev)
387                         break;
388         }
389
390         if (tz != pos1 || cdev != pos2)
391                 return -EINVAL;
392
393         dev =
394             kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
395         if (!dev)
396                 return -ENOMEM;
397         dev->tz = tz;
398         dev->cdev = cdev;
399         dev->trip = trip;
400         result = get_idr(&tz->idr, &tz->lock, &dev->id);
401         if (result)
402                 goto free_mem;
403
404         sprintf(dev->name, "cdev%d", dev->id);
405         result =
406             sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
407         if (result)
408                 goto release_idr;
409
410         sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
411         dev->attr.attr.name = dev->attr_name;
412         dev->attr.attr.mode = 0444;
413         dev->attr.show = thermal_cooling_device_trip_point_show;
414         result = device_create_file(&tz->device, &dev->attr);
415         if (result)
416                 goto remove_symbol_link;
417
418         mutex_lock(&tz->lock);
419         list_for_each_entry(pos, &tz->cooling_devices, node)
420             if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
421                 result = -EEXIST;
422                 break;
423         }
424         if (!result)
425                 list_add_tail(&dev->node, &tz->cooling_devices);
426         mutex_unlock(&tz->lock);
427
428         if (!result)
429                 return 0;
430
431         device_remove_file(&tz->device, &dev->attr);
432       remove_symbol_link:
433         sysfs_remove_link(&tz->device.kobj, dev->name);
434       release_idr:
435         release_idr(&tz->idr, &tz->lock, dev->id);
436       free_mem:
437         kfree(dev);
438         return result;
439 }
440
441 EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
442
443 /**
444  * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
445  * @tz:         thermal zone device
446  * @trip:       indicates which trip point the cooling devices is
447  *              associated with in this thermal zone.
448  * @cdev:       thermal cooling device
449  *
450  * This function is usually called in the thermal zone device .unbind callback.
451  */
452 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
453                                        int trip,
454                                        struct thermal_cooling_device *cdev)
455 {
456         struct thermal_cooling_device_instance *pos, *next;
457
458         mutex_lock(&tz->lock);
459         list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
460                 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
461                         list_del(&pos->node);
462                         mutex_unlock(&tz->lock);
463                         goto unbind;
464                 }
465         }
466         mutex_unlock(&tz->lock);
467
468         return -ENODEV;
469
470       unbind:
471         device_remove_file(&tz->device, &pos->attr);
472         sysfs_remove_link(&tz->device.kobj, pos->name);
473         release_idr(&tz->idr, &tz->lock, pos->id);
474         kfree(pos);
475         return 0;
476 }
477
478 EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
479
480 static void thermal_release(struct device *dev)
481 {
482         struct thermal_zone_device *tz;
483         struct thermal_cooling_device *cdev;
484
485         if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) {
486                 tz = to_thermal_zone(dev);
487                 kfree(tz);
488         } else {
489                 cdev = to_cooling_device(dev);
490                 kfree(cdev);
491         }
492 }
493
494 static struct class thermal_class = {
495         .name = "thermal",
496         .dev_release = thermal_release,
497 };
498
499 /**
500  * thermal_cooling_device_register - register a new thermal cooling device
501  * @type:       the thermal cooling device type.
502  * @devdata:    device private data.
503  * @ops:                standard thermal cooling devices callbacks.
504  */
505 struct thermal_cooling_device *thermal_cooling_device_register(char *type,
506                                                                void *devdata,
507                                                                struct
508                                                                thermal_cooling_device_ops
509                                                                *ops)
510 {
511         struct thermal_cooling_device *cdev;
512         struct thermal_zone_device *pos;
513         int result;
514
515         if (!type)
516                 return ERR_PTR(-EINVAL);
517
518         if (strlen(type) >= THERMAL_NAME_LENGTH)
519                 return ERR_PTR(-EINVAL);
520
521         if (!ops || !ops->get_max_state || !ops->get_cur_state ||
522             !ops->set_cur_state)
523                 return ERR_PTR(-EINVAL);
524
525         cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
526         if (!cdev)
527                 return ERR_PTR(-ENOMEM);
528
529         result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
530         if (result) {
531                 kfree(cdev);
532                 return ERR_PTR(result);
533         }
534
535         strcpy(cdev->type, type);
536         cdev->ops = ops;
537         cdev->device.class = &thermal_class;
538         cdev->devdata = devdata;
539         sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id);
540         result = device_register(&cdev->device);
541         if (result) {
542                 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
543                 kfree(cdev);
544                 return ERR_PTR(result);
545         }
546
547         /* sys I/F */
548         result = device_create_file(&cdev->device, &dev_attr_cdev_type);
549         if (result)
550                 goto unregister;
551
552         result = device_create_file(&cdev->device, &dev_attr_max_state);
553         if (result)
554                 goto unregister;
555
556         result = device_create_file(&cdev->device, &dev_attr_cur_state);
557         if (result)
558                 goto unregister;
559
560         mutex_lock(&thermal_list_lock);
561         list_add(&cdev->node, &thermal_cdev_list);
562         list_for_each_entry(pos, &thermal_tz_list, node) {
563                 if (!pos->ops->bind)
564                         continue;
565                 result = pos->ops->bind(pos, cdev);
566                 if (result)
567                         break;
568
569         }
570         mutex_unlock(&thermal_list_lock);
571
572         if (!result)
573                 return cdev;
574
575       unregister:
576         release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
577         device_unregister(&cdev->device);
578         return ERR_PTR(result);
579 }
580
581 EXPORT_SYMBOL(thermal_cooling_device_register);
582
583 /**
584  * thermal_cooling_device_unregister - removes the registered thermal cooling device
585  * @cdev:       the thermal cooling device to remove.
586  *
587  * thermal_cooling_device_unregister() must be called when the device is no
588  * longer needed.
589  */
590 void thermal_cooling_device_unregister(struct
591                                        thermal_cooling_device
592                                        *cdev)
593 {
594         struct thermal_zone_device *tz;
595         struct thermal_cooling_device *pos = NULL;
596
597         if (!cdev)
598                 return;
599
600         mutex_lock(&thermal_list_lock);
601         list_for_each_entry(pos, &thermal_cdev_list, node)
602             if (pos == cdev)
603                 break;
604         if (pos != cdev) {
605                 /* thermal cooling device not found */
606                 mutex_unlock(&thermal_list_lock);
607                 return;
608         }
609         list_del(&cdev->node);
610         list_for_each_entry(tz, &thermal_tz_list, node) {
611                 if (!tz->ops->unbind)
612                         continue;
613                 tz->ops->unbind(tz, cdev);
614         }
615         mutex_unlock(&thermal_list_lock);
616
617         device_remove_file(&cdev->device, &dev_attr_cdev_type);
618         device_remove_file(&cdev->device, &dev_attr_max_state);
619         device_remove_file(&cdev->device, &dev_attr_cur_state);
620
621         release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
622         device_unregister(&cdev->device);
623         return;
624 }
625
626 EXPORT_SYMBOL(thermal_cooling_device_unregister);
627
628 /**
629  * thermal_zone_device_register - register a new thermal zone device
630  * @type:       the thermal zone device type
631  * @trips:      the number of trip points the thermal zone support
632  * @devdata:    private device data
633  * @ops:        standard thermal zone device callbacks
634  *
635  * thermal_zone_device_unregister() must be called when the device is no
636  * longer needed.
637  */
638 struct thermal_zone_device *thermal_zone_device_register(char *type,
639                                                          int trips,
640                                                          void *devdata, struct
641                                                          thermal_zone_device_ops
642                                                          *ops)
643 {
644         struct thermal_zone_device *tz;
645         struct thermal_cooling_device *pos;
646         int result;
647         int count;
648
649         if (!type)
650                 return ERR_PTR(-EINVAL);
651
652         if (strlen(type) >= THERMAL_NAME_LENGTH)
653                 return ERR_PTR(-EINVAL);
654
655         if (trips > THERMAL_MAX_TRIPS || trips < 0)
656                 return ERR_PTR(-EINVAL);
657
658         if (!ops || !ops->get_temp)
659                 return ERR_PTR(-EINVAL);
660
661         tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
662         if (!tz)
663                 return ERR_PTR(-ENOMEM);
664
665         INIT_LIST_HEAD(&tz->cooling_devices);
666         idr_init(&tz->idr);
667         mutex_init(&tz->lock);
668         result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
669         if (result) {
670                 kfree(tz);
671                 return ERR_PTR(result);
672         }
673         if (tz->id >= MAX_THERMAL_ZONES) {
674                 printk(KERN_ERR PREFIX
675                         "Too many thermal zones\n");
676                 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
677                 kfree(tz);
678                 return ERR_PTR(-EINVAL);
679         }
680
681         strcpy(tz->type, type);
682         tz->ops = ops;
683         tz->device.class = &thermal_class;
684         tz->devdata = devdata;
685         tz->trips = trips;
686         sprintf(tz->device.bus_id, "thermal_zone%d", tz->id);
687         result = device_register(&tz->device);
688         if (result) {
689                 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
690                 kfree(tz);
691                 return ERR_PTR(result);
692         }
693
694         /* hwmon sys I/F */
695         result = device_create_file(thermal_hwmon,
696                                         &sensor_attrs[tz->id * 2].dev_attr);
697         if (result)
698                 goto unregister;
699
700         if (trips > 0) {
701                 char buf[40];
702                 result = tz->ops->get_trip_type(tz, 0, buf);
703                 if (result > 0 && !strcmp(buf, "critical\n")) {
704                         result = device_create_file(thermal_hwmon,
705                                         &sensor_attrs[tz->id * 2 + 1].dev_attr);
706                         if (result)
707                                 goto unregister;
708                 }
709         }
710
711         /* sys I/F */
712         result = device_create_file(&tz->device, &dev_attr_type);
713         if (result)
714                 goto unregister;
715
716         result = device_create_file(&tz->device, &dev_attr_temp);
717         if (result)
718                 goto unregister;
719
720         if (ops->get_mode) {
721                 result = device_create_file(&tz->device, &dev_attr_mode);
722                 if (result)
723                         goto unregister;
724         }
725
726         for (count = 0; count < trips; count++) {
727                 TRIP_POINT_ATTR_ADD(&tz->device, count, result);
728                 if (result)
729                         goto unregister;
730         }
731
732         mutex_lock(&thermal_list_lock);
733         list_add_tail(&tz->node, &thermal_tz_list);
734         if (ops->bind)
735                 list_for_each_entry(pos, &thermal_cdev_list, node) {
736                 result = ops->bind(tz, pos);
737                 if (result)
738                         break;
739                 }
740         mutex_unlock(&thermal_list_lock);
741
742         if (!result)
743                 return tz;
744
745       unregister:
746         release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
747         device_unregister(&tz->device);
748         return ERR_PTR(result);
749 }
750
751 EXPORT_SYMBOL(thermal_zone_device_register);
752
753 /**
754  * thermal_device_unregister - removes the registered thermal zone device
755  * @tz: the thermal zone device to remove
756  */
757 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
758 {
759         struct thermal_cooling_device *cdev;
760         struct thermal_zone_device *pos = NULL;
761         int count;
762
763         if (!tz)
764                 return;
765
766         mutex_lock(&thermal_list_lock);
767         list_for_each_entry(pos, &thermal_tz_list, node)
768             if (pos == tz)
769                 break;
770         if (pos != tz) {
771                 /* thermal zone device not found */
772                 mutex_unlock(&thermal_list_lock);
773                 return;
774         }
775         list_del(&tz->node);
776         if (tz->ops->unbind)
777                 list_for_each_entry(cdev, &thermal_cdev_list, node)
778                     tz->ops->unbind(tz, cdev);
779         mutex_unlock(&thermal_list_lock);
780
781         device_remove_file(thermal_hwmon,
782                                 &sensor_attrs[tz->id * 2].dev_attr);
783         if (tz->trips > 0) {
784                 char buf[40];
785                 if (tz->ops->get_trip_type(tz, 0, buf) > 0)
786                         if (!strcmp(buf, "critical\n"))
787                                 device_remove_file(thermal_hwmon,
788                                 &sensor_attrs[tz->id * 2 + 1].dev_attr);
789         }
790
791         device_remove_file(&tz->device, &dev_attr_type);
792         device_remove_file(&tz->device, &dev_attr_temp);
793         if (tz->ops->get_mode)
794                 device_remove_file(&tz->device, &dev_attr_mode);
795
796         for (count = 0; count < tz->trips; count++)
797                 TRIP_POINT_ATTR_REMOVE(&tz->device, count);
798
799         release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
800         idr_destroy(&tz->idr);
801         mutex_destroy(&tz->lock);
802         device_unregister(&tz->device);
803         return;
804 }
805
806 EXPORT_SYMBOL(thermal_zone_device_unregister);
807
808 static void thermal_exit(void)
809 {
810         if (thermal_hwmon) {
811                 device_remove_file(thermal_hwmon, &dev_attr_name);
812                 hwmon_device_unregister(thermal_hwmon);
813         }
814         class_unregister(&thermal_class);
815         idr_destroy(&thermal_tz_idr);
816         idr_destroy(&thermal_cdev_idr);
817         mutex_destroy(&thermal_idr_lock);
818         mutex_destroy(&thermal_list_lock);
819 }
820
821 static int __init thermal_init(void)
822 {
823         int result = 0;
824
825         result = class_register(&thermal_class);
826         if (result) {
827                 idr_destroy(&thermal_tz_idr);
828                 idr_destroy(&thermal_cdev_idr);
829                 mutex_destroy(&thermal_idr_lock);
830                 mutex_destroy(&thermal_list_lock);
831         }
832
833         thermal_hwmon = hwmon_device_register(NULL);
834         if (IS_ERR(thermal_hwmon)) {
835                 result = PTR_ERR(thermal_hwmon);
836                 thermal_hwmon = NULL;
837                 printk(KERN_ERR PREFIX
838                         "unable to register hwmon device\n");
839                 thermal_exit();
840                 return result;
841         }
842
843         result = device_create_file(thermal_hwmon, &dev_attr_name);
844
845         return result;
846 }
847
848 subsys_initcall(thermal_init);
849 module_exit(thermal_exit);