| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * gpio-fan.c - Hwmon driver for fans connected to GPIO lines. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2010 LaCie |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Simon Guinot <sguinot@lacie.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 | | - * You should have received a copy of the GNU General Public License |
|---|
| 19 | | - * along with this program; if not, write to the Free Software |
|---|
| 20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 21 | 8 | */ |
|---|
| 22 | 9 | |
|---|
| 23 | 10 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 67 | 54 | struct gpio_fan_data *fan_data = |
|---|
| 68 | 55 | container_of(ws, struct gpio_fan_data, alarm_work); |
|---|
| 69 | 56 | |
|---|
| 70 | | - sysfs_notify(&fan_data->dev->kobj, NULL, "fan1_alarm"); |
|---|
| 71 | | - kobject_uevent(&fan_data->dev->kobj, KOBJ_CHANGE); |
|---|
| 57 | + sysfs_notify(&fan_data->hwmon_dev->kobj, NULL, "fan1_alarm"); |
|---|
| 58 | + kobject_uevent(&fan_data->hwmon_dev->kobj, KOBJ_CHANGE); |
|---|
| 72 | 59 | } |
|---|
| 73 | 60 | |
|---|
| 74 | 61 | static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id) |
|---|
| .. | .. |
|---|
| 307 | 294 | static DEVICE_ATTR_RO(fan1_min); |
|---|
| 308 | 295 | static DEVICE_ATTR_RO(fan1_max); |
|---|
| 309 | 296 | static DEVICE_ATTR_RO(fan1_input); |
|---|
| 310 | | -static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, fan1_input_show, set_rpm); |
|---|
| 297 | +static DEVICE_ATTR(fan1_target, 0644, fan1_input_show, set_rpm); |
|---|
| 311 | 298 | |
|---|
| 312 | 299 | static umode_t gpio_fan_is_visible(struct kobject *kobj, |
|---|
| 313 | 300 | struct attribute *attr, int index) |
|---|
| .. | .. |
|---|
| 404 | 391 | if (!fan_data) |
|---|
| 405 | 392 | return -EINVAL; |
|---|
| 406 | 393 | |
|---|
| 394 | + if (state >= fan_data->num_speed) |
|---|
| 395 | + return -EINVAL; |
|---|
| 396 | + |
|---|
| 407 | 397 | set_fan_speed(fan_data, state); |
|---|
| 408 | 398 | return 0; |
|---|
| 409 | 399 | } |
|---|
| .. | .. |
|---|
| 498 | 488 | }; |
|---|
| 499 | 489 | MODULE_DEVICE_TABLE(of, of_gpio_fan_match); |
|---|
| 500 | 490 | |
|---|
| 491 | +static void gpio_fan_stop(void *data) |
|---|
| 492 | +{ |
|---|
| 493 | + set_fan_speed(data, 0); |
|---|
| 494 | +} |
|---|
| 495 | + |
|---|
| 501 | 496 | static int gpio_fan_probe(struct platform_device *pdev) |
|---|
| 502 | 497 | { |
|---|
| 503 | 498 | int err; |
|---|
| .. | .. |
|---|
| 518 | 513 | platform_set_drvdata(pdev, fan_data); |
|---|
| 519 | 514 | mutex_init(&fan_data->lock); |
|---|
| 520 | 515 | |
|---|
| 521 | | - /* Configure alarm GPIO if available. */ |
|---|
| 522 | | - if (fan_data->alarm_gpio) { |
|---|
| 523 | | - err = fan_alarm_init(fan_data); |
|---|
| 524 | | - if (err) |
|---|
| 525 | | - return err; |
|---|
| 526 | | - } |
|---|
| 527 | | - |
|---|
| 528 | 516 | /* Configure control GPIOs if available. */ |
|---|
| 529 | 517 | if (fan_data->gpios && fan_data->num_gpios > 0) { |
|---|
| 530 | 518 | if (!fan_data->speed || fan_data->num_speed <= 1) |
|---|
| 531 | 519 | return -EINVAL; |
|---|
| 532 | 520 | err = fan_ctrl_init(fan_data); |
|---|
| 521 | + if (err) |
|---|
| 522 | + return err; |
|---|
| 523 | + err = devm_add_action_or_reset(dev, gpio_fan_stop, fan_data); |
|---|
| 533 | 524 | if (err) |
|---|
| 534 | 525 | return err; |
|---|
| 535 | 526 | } |
|---|
| .. | .. |
|---|
| 542 | 533 | if (IS_ERR(fan_data->hwmon_dev)) |
|---|
| 543 | 534 | return PTR_ERR(fan_data->hwmon_dev); |
|---|
| 544 | 535 | |
|---|
| 536 | + /* Configure alarm GPIO if available. */ |
|---|
| 537 | + if (fan_data->alarm_gpio) { |
|---|
| 538 | + err = fan_alarm_init(fan_data); |
|---|
| 539 | + if (err) |
|---|
| 540 | + return err; |
|---|
| 541 | + } |
|---|
| 542 | + |
|---|
| 545 | 543 | /* Optional cooling device register for Device tree platforms */ |
|---|
| 546 | | - fan_data->cdev = thermal_of_cooling_device_register(np, |
|---|
| 547 | | - "gpio-fan", |
|---|
| 548 | | - fan_data, |
|---|
| 549 | | - &gpio_fan_cool_ops); |
|---|
| 544 | + fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np, |
|---|
| 545 | + "gpio-fan", fan_data, &gpio_fan_cool_ops); |
|---|
| 550 | 546 | |
|---|
| 551 | 547 | dev_info(dev, "GPIO fan initialized\n"); |
|---|
| 552 | 548 | |
|---|
| 553 | 549 | return 0; |
|---|
| 554 | 550 | } |
|---|
| 555 | 551 | |
|---|
| 556 | | -static int gpio_fan_remove(struct platform_device *pdev) |
|---|
| 552 | +static void gpio_fan_shutdown(struct platform_device *pdev) |
|---|
| 557 | 553 | { |
|---|
| 558 | 554 | struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); |
|---|
| 559 | 555 | |
|---|
| 560 | | - if (!IS_ERR(fan_data->cdev)) |
|---|
| 561 | | - thermal_cooling_device_unregister(fan_data->cdev); |
|---|
| 562 | | - |
|---|
| 563 | 556 | if (fan_data->gpios) |
|---|
| 564 | 557 | set_fan_speed(fan_data, 0); |
|---|
| 565 | | - |
|---|
| 566 | | - return 0; |
|---|
| 567 | | -} |
|---|
| 568 | | - |
|---|
| 569 | | -static void gpio_fan_shutdown(struct platform_device *pdev) |
|---|
| 570 | | -{ |
|---|
| 571 | | - gpio_fan_remove(pdev); |
|---|
| 572 | 558 | } |
|---|
| 573 | 559 | |
|---|
| 574 | 560 | #ifdef CONFIG_PM_SLEEP |
|---|
| .. | .. |
|---|
| 602 | 588 | |
|---|
| 603 | 589 | static struct platform_driver gpio_fan_driver = { |
|---|
| 604 | 590 | .probe = gpio_fan_probe, |
|---|
| 605 | | - .remove = gpio_fan_remove, |
|---|
| 606 | 591 | .shutdown = gpio_fan_shutdown, |
|---|
| 607 | 592 | .driver = { |
|---|
| 608 | 593 | .name = "gpio-fan", |
|---|