Skip to content

Commit b5cf88e

Browse files
nmenongroeck
authored andcommitted
(gpio-fan): Add thermal control hooks
Allow gpio-fan to be used as thermal cooling device for platforms that use GPIO maps to control fans. As part of this change, we make the shutdown and remove logic the same as well. Signed-off-by: Nishanth Menon <nm@ti.com> Acked-by: Eduardo Valentin <edubezval@gmail.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
1 parent b6bddec commit b5cf88e

2 files changed

Lines changed: 89 additions & 7 deletions

File tree

Documentation/devicetree/bindings/gpio/gpio-fan.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ Optional properties:
1111
must have the RPM values in ascending order.
1212
- alarm-gpios: This pin going active indicates something is wrong with
1313
the fan, and a udev event will be fired.
14+
- cooling-cells: If used as a cooling device, must be <2>
15+
Also see: Documentation/devicetree/bindings/thermal/thermal.txt
16+
min and max states are derived from the speed-map of the fan.
1417

1518
Note: At least one the "gpios" or "alarm-gpios" properties must be set.
1619

@@ -25,3 +28,13 @@ Examples:
2528
6000 2>;
2629
alarm-gpios = <&gpio1 15 1>;
2730
};
31+
gpio_fan_cool: gpio_fan {
32+
compatible = "gpio-fan";
33+
gpios = <&gpio2 14 1
34+
&gpio2 13 1>;
35+
gpio-fan,speed-map = <0 0>,
36+
<3000 1>,
37+
<6000 2>;
38+
alarm-gpios = <&gpio2 15 1>;
39+
#cooling-cells = <2>; /* min followed by max */
40+
};

drivers/hwmon/gpio-fan.c

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@
3434
#include <linux/of.h>
3535
#include <linux/of_platform.h>
3636
#include <linux/of_gpio.h>
37+
#include <linux/thermal.h>
3738

3839
struct gpio_fan_data {
3940
struct platform_device *pdev;
4041
struct device *hwmon_dev;
42+
/* Cooling device if any */
43+
struct thermal_cooling_device *cdev;
4144
struct mutex lock; /* lock GPIOs operations. */
4245
int num_ctrl;
4346
unsigned *ctrl;
@@ -387,6 +390,53 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
387390
return 0;
388391
}
389392

393+
static int gpio_fan_get_max_state(struct thermal_cooling_device *cdev,
394+
unsigned long *state)
395+
{
396+
struct gpio_fan_data *fan_data = cdev->devdata;
397+
398+
if (!fan_data)
399+
return -EINVAL;
400+
401+
*state = fan_data->num_speed - 1;
402+
return 0;
403+
}
404+
405+
static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev,
406+
unsigned long *state)
407+
{
408+
struct gpio_fan_data *fan_data = cdev->devdata;
409+
int r;
410+
411+
if (!fan_data)
412+
return -EINVAL;
413+
414+
r = get_fan_speed_index(fan_data);
415+
if (r < 0)
416+
return r;
417+
418+
*state = r;
419+
return 0;
420+
}
421+
422+
static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev,
423+
unsigned long state)
424+
{
425+
struct gpio_fan_data *fan_data = cdev->devdata;
426+
427+
if (!fan_data)
428+
return -EINVAL;
429+
430+
set_fan_speed(fan_data, state);
431+
return 0;
432+
}
433+
434+
static const struct thermal_cooling_device_ops gpio_fan_cool_ops = {
435+
.get_max_state = gpio_fan_get_max_state,
436+
.get_cur_state = gpio_fan_get_cur_state,
437+
.set_cur_state = gpio_fan_set_cur_state,
438+
};
439+
390440
#ifdef CONFIG_OF_GPIO
391441
/*
392442
* Translate OpenFirmware node properties into platform_data
@@ -497,6 +547,11 @@ static int gpio_fan_probe(struct platform_device *pdev)
497547
struct gpio_fan_data *fan_data;
498548
struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev);
499549

550+
fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
551+
GFP_KERNEL);
552+
if (!fan_data)
553+
return -ENOMEM;
554+
500555
#ifdef CONFIG_OF_GPIO
501556
if (!pdata) {
502557
pdata = devm_kzalloc(&pdev->dev,
@@ -508,17 +563,20 @@ static int gpio_fan_probe(struct platform_device *pdev)
508563
err = gpio_fan_get_of_pdata(&pdev->dev, pdata);
509564
if (err)
510565
return err;
566+
/* Optional cooling device register for Device tree platforms */
567+
fan_data->cdev =
568+
thermal_of_cooling_device_register(pdev->dev.of_node,
569+
"gpio-fan", fan_data,
570+
&gpio_fan_cool_ops);
511571
}
512572
#else /* CONFIG_OF_GPIO */
513573
if (!pdata)
514574
return -EINVAL;
575+
/* Optional cooling device register for non Device tree platforms */
576+
fan_data->cdev = thermal_cooling_device_register("gpio-fan", fan_data,
577+
&gpio_fan_cool_ops);
515578
#endif /* CONFIG_OF_GPIO */
516579

517-
fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
518-
GFP_KERNEL);
519-
if (!fan_data)
520-
return -ENOMEM;
521-
522580
fan_data->pdev = pdev;
523581
platform_set_drvdata(pdev, fan_data);
524582
mutex_init(&fan_data->lock);
@@ -552,12 +610,22 @@ static int gpio_fan_probe(struct platform_device *pdev)
552610
return 0;
553611
}
554612

555-
static void gpio_fan_shutdown(struct platform_device *pdev)
613+
static int gpio_fan_remove(struct platform_device *pdev)
556614
{
557-
struct gpio_fan_data *fan_data = dev_get_drvdata(&pdev->dev);
615+
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
616+
617+
if (!IS_ERR(fan_data->cdev))
618+
thermal_cooling_device_unregister(fan_data->cdev);
558619

559620
if (fan_data->ctrl)
560621
set_fan_speed(fan_data, 0);
622+
623+
return 0;
624+
}
625+
626+
static void gpio_fan_shutdown(struct platform_device *pdev)
627+
{
628+
gpio_fan_remove(pdev);
561629
}
562630

563631
#ifdef CONFIG_PM_SLEEP
@@ -591,6 +659,7 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
591659

592660
static struct platform_driver gpio_fan_driver = {
593661
.probe = gpio_fan_probe,
662+
.remove = gpio_fan_remove,
594663
.shutdown = gpio_fan_shutdown,
595664
.driver = {
596665
.name = "gpio-fan",

0 commit comments

Comments
 (0)