1 /* 2 * pwm-fan.c - Hwmon driver for fans connected to PWM lines. 3 * 4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. 5 * 6 * Author: Kamil Debski <k.debski@samsung.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include <linux/hwmon.h> 20 #include <linux/hwmon-sysfs.h> 21 #include <linux/module.h> 22 #include <linux/mutex.h> 23 #include <linux/of.h> 24 #include <linux/platform_device.h> 25 #include <linux/pwm.h> 26 #include <linux/sysfs.h> 27 #include <linux/thermal.h> 28 29 #define MAX_PWM 255 30 31 struct pwm_fan_ctx { 32 struct mutex lock; 33 struct pwm_device *pwm; 34 unsigned int pwm_value; 35 unsigned int pwm_fan_state; 36 unsigned int pwm_fan_max_state; 37 unsigned int *pwm_fan_cooling_levels; 38 struct thermal_cooling_device *cdev; 39 }; 40 41 static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) 42 { 43 struct pwm_args pargs; 44 unsigned long duty; 45 int ret = 0; 46 47 pwm_get_args(ctx->pwm, &pargs); 48 49 mutex_lock(&ctx->lock); 50 if (ctx->pwm_value == pwm) 51 goto exit_set_pwm_err; 52 53 duty = DIV_ROUND_UP(pwm * (pargs.period - 1), MAX_PWM); 54 ret = pwm_config(ctx->pwm, duty, pargs.period); 55 if (ret) 56 goto exit_set_pwm_err; 57 58 if (pwm == 0) 59 pwm_disable(ctx->pwm); 60 61 if (ctx->pwm_value == 0) { 62 ret = pwm_enable(ctx->pwm); 63 if (ret) 64 goto exit_set_pwm_err; 65 } 66 67 ctx->pwm_value = pwm; 68 exit_set_pwm_err: 69 mutex_unlock(&ctx->lock); 70 return ret; 71 } 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 84 static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, 85 const char *buf, size_t count) 86 { 87 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); 88 unsigned long pwm; 89 int ret; 90 91 if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM) 92 return -EINVAL; 93 94 ret = __set_pwm(ctx, pwm); 95 if (ret) 96 return ret; 97 98 pwm_fan_update_state(ctx, pwm); 99 return count; 100 } 101 102 static ssize_t show_pwm(struct device *dev, 103 struct device_attribute *attr, char *buf) 104 { 105 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); 106 107 return sprintf(buf, "%u\n", ctx->pwm_value); 108 } 109 110 111 static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0); 112 113 static struct attribute *pwm_fan_attrs[] = { 114 &sensor_dev_attr_pwm1.dev_attr.attr, 115 NULL, 116 }; 117 118 ATTRIBUTE_GROUPS(pwm_fan); 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 176 static int pwm_fan_of_get_cooling_data(struct device *dev, 177 struct pwm_fan_ctx *ctx) 178 { 179 struct device_node *np = dev->of_node; 180 int num, i, ret; 181 182 if (!of_find_property(np, "cooling-levels", NULL)) 183 return 0; 184 185 ret = of_property_count_u32_elems(np, "cooling-levels"); 186 if (ret <= 0) { 187 dev_err(dev, "Wrong data!\n"); 188 return ret ? : -EINVAL; 189 } 190 191 num = ret; 192 ctx->pwm_fan_cooling_levels = devm_kzalloc(dev, num * sizeof(u32), 193 GFP_KERNEL); 194 if (!ctx->pwm_fan_cooling_levels) 195 return -ENOMEM; 196 197 ret = of_property_read_u32_array(np, "cooling-levels", 198 ctx->pwm_fan_cooling_levels, num); 199 if (ret) { 200 dev_err(dev, "Property 'cooling-levels' cannot be read!\n"); 201 return ret; 202 } 203 204 for (i = 0; i < num; i++) { 205 if (ctx->pwm_fan_cooling_levels[i] > MAX_PWM) { 206 dev_err(dev, "PWM fan state[%d]:%d > %d\n", i, 207 ctx->pwm_fan_cooling_levels[i], MAX_PWM); 208 return -EINVAL; 209 } 210 } 211 212 ctx->pwm_fan_max_state = num - 1; 213 214 return 0; 215 } 216 217 static int pwm_fan_probe(struct platform_device *pdev) 218 { 219 struct thermal_cooling_device *cdev; 220 struct pwm_fan_ctx *ctx; 221 struct pwm_args pargs; 222 struct device *hwmon; 223 int duty_cycle; 224 int ret; 225 226 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 227 if (!ctx) 228 return -ENOMEM; 229 230 mutex_init(&ctx->lock); 231 232 ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL); 233 if (IS_ERR(ctx->pwm)) { 234 dev_err(&pdev->dev, "Could not get PWM\n"); 235 return PTR_ERR(ctx->pwm); 236 } 237 238 platform_set_drvdata(pdev, ctx); 239 240 /* 241 * FIXME: pwm_apply_args() should be removed when switching to the 242 * atomic PWM API. 243 */ 244 pwm_apply_args(ctx->pwm); 245 246 /* Set duty cycle to maximum allowed */ 247 pwm_get_args(ctx->pwm, &pargs); 248 249 duty_cycle = pargs.period - 1; 250 ctx->pwm_value = MAX_PWM; 251 252 ret = pwm_config(ctx->pwm, duty_cycle, pargs.period); 253 if (ret) { 254 dev_err(&pdev->dev, "Failed to configure PWM\n"); 255 return ret; 256 } 257 258 /* Enbale PWM output */ 259 ret = pwm_enable(ctx->pwm); 260 if (ret) { 261 dev_err(&pdev->dev, "Failed to enable PWM\n"); 262 return ret; 263 } 264 265 hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan", 266 ctx, pwm_fan_groups); 267 if (IS_ERR(hwmon)) { 268 dev_err(&pdev->dev, "Failed to register hwmon device\n"); 269 pwm_disable(ctx->pwm); 270 return PTR_ERR(hwmon); 271 } 272 273 ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx); 274 if (ret) 275 return ret; 276 277 ctx->pwm_fan_state = ctx->pwm_fan_max_state; 278 if (IS_ENABLED(CONFIG_THERMAL)) { 279 cdev = thermal_of_cooling_device_register(pdev->dev.of_node, 280 "pwm-fan", ctx, 281 &pwm_fan_cooling_ops); 282 if (IS_ERR(cdev)) { 283 dev_err(&pdev->dev, 284 "Failed to register pwm-fan as cooling device"); 285 pwm_disable(ctx->pwm); 286 return PTR_ERR(cdev); 287 } 288 ctx->cdev = cdev; 289 thermal_cdev_update(cdev); 290 } 291 292 return 0; 293 } 294 295 static int pwm_fan_remove(struct platform_device *pdev) 296 { 297 struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); 298 299 thermal_cooling_device_unregister(ctx->cdev); 300 if (ctx->pwm_value) 301 pwm_disable(ctx->pwm); 302 return 0; 303 } 304 305 #ifdef CONFIG_PM_SLEEP 306 static int pwm_fan_suspend(struct device *dev) 307 { 308 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); 309 310 if (ctx->pwm_value) 311 pwm_disable(ctx->pwm); 312 return 0; 313 } 314 315 static int pwm_fan_resume(struct device *dev) 316 { 317 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); 318 struct pwm_args pargs; 319 unsigned long duty; 320 int ret; 321 322 if (ctx->pwm_value == 0) 323 return 0; 324 325 pwm_get_args(ctx->pwm, &pargs); 326 duty = DIV_ROUND_UP(ctx->pwm_value * (pargs.period - 1), MAX_PWM); 327 ret = pwm_config(ctx->pwm, duty, pargs.period); 328 if (ret) 329 return ret; 330 return pwm_enable(ctx->pwm); 331 } 332 #endif 333 334 static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); 335 336 static const struct of_device_id of_pwm_fan_match[] = { 337 { .compatible = "pwm-fan", }, 338 {}, 339 }; 340 MODULE_DEVICE_TABLE(of, of_pwm_fan_match); 341 342 static struct platform_driver pwm_fan_driver = { 343 .probe = pwm_fan_probe, 344 .remove = pwm_fan_remove, 345 .driver = { 346 .name = "pwm-fan", 347 .pm = &pwm_fan_pm, 348 .of_match_table = of_pwm_fan_match, 349 }, 350 }; 351 352 module_platform_driver(pwm_fan_driver); 353 354 MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); 355 MODULE_ALIAS("platform:pwm-fan"); 356 MODULE_DESCRIPTION("PWM FAN driver"); 357 MODULE_LICENSE("GPL"); 358