diff options
author | Lukasz Majewski <l.majewski@samsung.com> | 2015-02-26 08:59:37 -0500 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2015-03-09 12:59:36 -0400 |
commit | b6bddec01932b94a20b6a7bbb7ed9d98e82ec162 (patch) | |
tree | 3c212f1008dde7291f297a88b2cb78b14aee1b24 /drivers/hwmon/pwm-fan.c | |
parent | 2e5219c77183be47eb9ae4b1a4195e008d196c73 (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.c | 89 |
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 | ||
39 | static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) | 41 | static 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 | ||
73 | static 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 | |||
71 | static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | 84 | static 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 | ||
104 | ATTRIBUTE_GROUPS(pwm_fan); | 118 | ATTRIBUTE_GROUPS(pwm_fan); |
105 | 119 | ||
120 | /* thermal cooling device callbacks */ | ||
121 | static 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 | |||
134 | static 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 | |||
147 | static int | ||
148 | pwm_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 | |||
170 | static 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 | |||
106 | int pwm_fan_of_get_cooling_data(struct device *dev, struct pwm_fan_ctx *ctx) | 176 | int 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 | ||
146 | static int pwm_fan_probe(struct platform_device *pdev) | 216 | static 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; |