]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/thermal/device_cooling.c
pwm: imx: support output polarity inversion
[karo-tx-linux.git] / drivers / thermal / device_cooling.c
1 /*
2  * Copyright (C) 2013 Freescale Semiconductor, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  */
9
10 #include <linux/module.h>
11 #include <linux/thermal.h>
12 #include <linux/err.h>
13 #include <linux/slab.h>
14
15 struct devfreq_cooling_device {
16         int id;
17         struct thermal_cooling_device *cool_dev;
18         unsigned int devfreq_state;
19 };
20
21 static DEFINE_IDR(devfreq_idr);
22 static DEFINE_MUTEX(devfreq_cooling_lock);
23
24 #define MAX_STATE       1
25
26 static BLOCKING_NOTIFIER_HEAD(devfreq_cooling_chain_head);
27
28 int register_devfreq_cooling_notifier(struct notifier_block *nb)
29 {
30         return blocking_notifier_chain_register(
31                 &devfreq_cooling_chain_head, nb);
32 }
33 EXPORT_SYMBOL_GPL(register_devfreq_cooling_notifier);
34
35 int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
36 {
37         return blocking_notifier_chain_unregister(
38                 &devfreq_cooling_chain_head, nb);
39 }
40 EXPORT_SYMBOL_GPL(unregister_devfreq_cooling_notifier);
41
42 static int devfreq_cooling_notifier_call_chain(unsigned long val)
43 {
44         return (blocking_notifier_call_chain(
45                 &devfreq_cooling_chain_head, val, NULL)
46                 == NOTIFY_BAD) ? -EINVAL : 0;
47 }
48
49 static int devfreq_set_cur_state(struct thermal_cooling_device *cdev,
50                                  unsigned long state)
51 {
52         struct devfreq_cooling_device *devfreq_device = cdev->devdata;
53         int ret;
54
55         ret = devfreq_cooling_notifier_call_chain(state);
56         if (ret)
57                 return -EINVAL;
58         devfreq_device->devfreq_state = state;
59
60         return 0;
61 }
62
63 static int devfreq_get_max_state(struct thermal_cooling_device *cdev,
64                                  unsigned long *state)
65 {
66         *state = MAX_STATE;
67
68         return 0;
69 }
70
71 static int devfreq_get_cur_state(struct thermal_cooling_device *cdev,
72                                  unsigned long *state)
73 {
74         struct devfreq_cooling_device *devfreq_device = cdev->devdata;
75
76         *state = devfreq_device->devfreq_state;
77
78         return 0;
79 }
80
81 static struct thermal_cooling_device_ops const devfreq_cooling_ops = {
82         .get_max_state = devfreq_get_max_state,
83         .get_cur_state = devfreq_get_cur_state,
84         .set_cur_state = devfreq_set_cur_state,
85 };
86
87 static int get_idr(struct idr *idr, int *id)
88 {
89         int ret;
90
91         mutex_lock(&devfreq_cooling_lock);
92         ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
93         mutex_unlock(&devfreq_cooling_lock);
94         if (unlikely(ret < 0))
95                 return ret;
96         *id = ret;
97
98         return 0;
99 }
100
101 static void release_idr(struct idr *idr, int id)
102 {
103         mutex_lock(&devfreq_cooling_lock);
104         idr_remove(idr, id);
105         mutex_unlock(&devfreq_cooling_lock);
106 }
107
108 struct thermal_cooling_device *devfreq_cooling_register(void)
109 {
110         struct thermal_cooling_device *cool_dev;
111         struct devfreq_cooling_device *devfreq_dev = NULL;
112         char dev_name[THERMAL_NAME_LENGTH];
113         int ret = 0;
114
115         devfreq_dev = kzalloc(sizeof(struct devfreq_cooling_device),
116                               GFP_KERNEL);
117         if (!devfreq_dev)
118                 return ERR_PTR(-ENOMEM);
119
120         ret = get_idr(&devfreq_idr, &devfreq_dev->id);
121         if (ret) {
122                 kfree(devfreq_dev);
123                 return ERR_PTR(-EINVAL);
124         }
125
126         snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d",
127                  devfreq_dev->id);
128
129         cool_dev = thermal_cooling_device_register(dev_name, devfreq_dev,
130                                                    &devfreq_cooling_ops);
131         if (!cool_dev) {
132                 release_idr(&devfreq_idr, devfreq_dev->id);
133                 kfree(devfreq_dev);
134                 return ERR_PTR(-EINVAL);
135         }
136         devfreq_dev->cool_dev = cool_dev;
137         devfreq_dev->devfreq_state = 0;
138
139         return cool_dev;
140 }
141 EXPORT_SYMBOL_GPL(devfreq_cooling_register);
142
143 void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
144 {
145         struct devfreq_cooling_device *devfreq_dev = cdev->devdata;
146
147         thermal_cooling_device_unregister(devfreq_dev->cool_dev);
148         release_idr(&devfreq_idr, devfreq_dev->id);
149         kfree(devfreq_dev);
150 }
151 EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);