aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pwm-fan.c
diff options
context:
space:
mode:
authorLukasz Majewski <l.majewski@samsung.com>2015-02-26 08:59:37 -0500
committerGuenter Roeck <linux@roeck-us.net>2015-03-09 12:59:36 -0400
commitb6bddec01932b94a20b6a7bbb7ed9d98e82ec162 (patch)
tree3c212f1008dde7291f297a88b2cb78b14aee1b24 /drivers/hwmon/pwm-fan.c
parent2e5219c77183be47eb9ae4b1a4195e008d196c73 (diff)
hwmon: (pwm-fan) Add support for using PWM FAN as a cooling device
The PWM FAN device can now be used as a thermal cooling device. Signed-off-by: Lukasz Majewski <l.majewski@samsung.com> Acked-by: Eduardo Valentin <edubezval@gmail.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/pwm-fan.c')
-rw-r--r--drivers/hwmon/pwm-fan.c89
1 files changed, 88 insertions, 1 deletions
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index e6ed3532deac..7c83dc4c8dbd 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -24,6 +24,7 @@
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/pwm.h> 25#include <linux/pwm.h>
26#include <linux/sysfs.h> 26#include <linux/sysfs.h>
27#include <linux/thermal.h>
27 28
28#define MAX_PWM 255 29#define MAX_PWM 255
29 30
@@ -34,6 +35,7 @@ struct pwm_fan_ctx {
34 unsigned int pwm_fan_state; 35 unsigned int pwm_fan_state;
35 unsigned int pwm_fan_max_state; 36 unsigned int pwm_fan_max_state;
36 unsigned int *pwm_fan_cooling_levels; 37 unsigned int *pwm_fan_cooling_levels;
38 struct thermal_cooling_device *cdev;
37}; 39};
38 40
39static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) 41static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
@@ -68,6 +70,17 @@ exit_set_pwm_err:
68 return ret; 70 return ret;
69} 71}
70 72
73static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm)
74{
75 int i;
76
77 for (i = 0; i < ctx->pwm_fan_max_state; ++i)
78 if (pwm < ctx->pwm_fan_cooling_levels[i + 1])
79 break;
80
81 ctx->pwm_fan_state = i;
82}
83
71static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, 84static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
72 const char *buf, size_t count) 85 const char *buf, size_t count)
73{ 86{
@@ -82,6 +95,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
82 if (ret) 95 if (ret)
83 return ret; 96 return ret;
84 97
98 pwm_fan_update_state(ctx, pwm);
85 return count; 99 return count;
86} 100}
87 101
@@ -103,6 +117,62 @@ static struct attribute *pwm_fan_attrs[] = {
103 117
104ATTRIBUTE_GROUPS(pwm_fan); 118ATTRIBUTE_GROUPS(pwm_fan);
105 119
120/* thermal cooling device callbacks */
121static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
122 unsigned long *state)
123{
124 struct pwm_fan_ctx *ctx = cdev->devdata;
125
126 if (!ctx)
127 return -EINVAL;
128
129 *state = ctx->pwm_fan_max_state;
130
131 return 0;
132}
133
134static int pwm_fan_get_cur_state(struct thermal_cooling_device *cdev,
135 unsigned long *state)
136{
137 struct pwm_fan_ctx *ctx = cdev->devdata;
138
139 if (!ctx)
140 return -EINVAL;
141
142 *state = ctx->pwm_fan_state;
143
144 return 0;
145}
146
147static int
148pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
149{
150 struct pwm_fan_ctx *ctx = cdev->devdata;
151 int ret;
152
153 if (!ctx || (state > ctx->pwm_fan_max_state))
154 return -EINVAL;
155
156 if (state == ctx->pwm_fan_state)
157 return 0;
158
159 ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]);
160 if (ret) {
161 dev_err(&cdev->device, "Cannot set pwm!\n");
162 return ret;
163 }
164
165 ctx->pwm_fan_state = state;
166
167 return ret;
168}
169
170static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = {
171 .get_max_state = pwm_fan_get_max_state,
172 .get_cur_state = pwm_fan_get_cur_state,
173 .set_cur_state = pwm_fan_set_cur_state,
174};
175
106int pwm_fan_of_get_cooling_data(struct device *dev, struct pwm_fan_ctx *ctx) 176int pwm_fan_of_get_cooling_data(struct device *dev, struct pwm_fan_ctx *ctx)
107{ 177{
108 struct device_node *np = dev->of_node; 178 struct device_node *np = dev->of_node;
@@ -145,8 +215,9 @@ int pwm_fan_of_get_cooling_data(struct device *dev, struct pwm_fan_ctx *ctx)
145 215
146static int pwm_fan_probe(struct platform_device *pdev) 216static int pwm_fan_probe(struct platform_device *pdev)
147{ 217{
148 struct device *hwmon; 218 struct thermal_cooling_device *cdev;
149 struct pwm_fan_ctx *ctx; 219 struct pwm_fan_ctx *ctx;
220 struct device *hwmon;
150 int duty_cycle; 221 int duty_cycle;
151 int ret; 222 int ret;
152 223
@@ -193,6 +264,21 @@ static int pwm_fan_probe(struct platform_device *pdev)
193 if (ret) 264 if (ret)
194 return ret; 265 return ret;
195 266
267 ctx->pwm_fan_state = ctx->pwm_fan_max_state;
268 if (IS_ENABLED(CONFIG_THERMAL)) {
269 cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
270 "pwm-fan", ctx,
271 &pwm_fan_cooling_ops);
272 if (IS_ERR(cdev)) {
273 dev_err(&pdev->dev,
274 "Failed to register pwm-fan as cooling device");
275 pwm_disable(ctx->pwm);
276 return PTR_ERR(cdev);
277 }
278 ctx->cdev = cdev;
279 thermal_cdev_update(cdev);
280 }
281
196 return 0; 282 return 0;
197} 283}
198 284
@@ -200,6 +286,7 @@ static int pwm_fan_remove(struct platform_device *pdev)
200{ 286{
201 struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); 287 struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
202 288
289 thermal_cooling_device_unregister(ctx->cdev);
203 if (ctx->pwm_value) 290 if (ctx->pwm_value)
204 pwm_disable(ctx->pwm); 291 pwm_disable(ctx->pwm);
205 return 0; 292 return 0;