1 // SPDX-License-Identifier: GPL-2.0+
3 * GPD Pocket fan controller driver
5 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
8 #include <linux/acpi.h>
9 #include <linux/devm-helpers.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/module.h>
12 #include <linux/moduleparam.h>
13 #include <linux/platform_device.h>
14 #include <linux/power_supply.h>
15 #include <linux/thermal.h>
16 #include <linux/workqueue.h>
20 #define TEMP_LIMIT0_DEFAULT 55000
21 #define TEMP_LIMIT1_DEFAULT 60000
22 #define TEMP_LIMIT2_DEFAULT 65000
24 #define HYSTERESIS_DEFAULT 3000
26 #define SPEED_ON_AC_DEFAULT 2
28 static int temp_limits
[3] = {
29 TEMP_LIMIT0_DEFAULT
, TEMP_LIMIT1_DEFAULT
, TEMP_LIMIT2_DEFAULT
,
31 module_param_array(temp_limits
, int, NULL
, 0444);
32 MODULE_PARM_DESC(temp_limits
,
33 "Millicelsius values above which the fan speed increases");
35 static int hysteresis
= HYSTERESIS_DEFAULT
;
36 module_param(hysteresis
, int, 0444);
37 MODULE_PARM_DESC(hysteresis
,
38 "Hysteresis in millicelsius before lowering the fan speed");
40 static int speed_on_ac
= SPEED_ON_AC_DEFAULT
;
41 module_param(speed_on_ac
, int, 0444);
42 MODULE_PARM_DESC(speed_on_ac
,
43 "minimum fan speed to allow when system is powered by AC");
45 struct gpd_pocket_fan_data
{
47 struct thermal_zone_device
*dts0
;
48 struct thermal_zone_device
*dts1
;
49 struct gpio_desc
*gpio0
;
50 struct gpio_desc
*gpio1
;
51 struct delayed_work work
;
55 static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data
*fan
, int speed
)
57 if (speed
== fan
->last_speed
)
60 gpiod_direction_output(fan
->gpio0
, !!(speed
& 1));
61 gpiod_direction_output(fan
->gpio1
, !!(speed
& 2));
63 fan
->last_speed
= speed
;
66 static int gpd_pocket_fan_min_speed(void)
68 if (power_supply_is_system_supplied())
74 static void gpd_pocket_fan_worker(struct work_struct
*work
)
76 struct gpd_pocket_fan_data
*fan
=
77 container_of(work
, struct gpd_pocket_fan_data
, work
.work
);
78 int t0
, t1
, temp
, speed
, min_speed
, i
;
80 if (thermal_zone_get_temp(fan
->dts0
, &t0
) ||
81 thermal_zone_get_temp(fan
->dts1
, &t1
)) {
82 dev_warn(fan
->dev
, "Error getting temperature\n");
89 speed
= fan
->last_speed
;
90 min_speed
= gpd_pocket_fan_min_speed();
92 /* Determine minimum speed */
93 for (i
= min_speed
; i
< ARRAY_SIZE(temp_limits
); i
++) {
94 if (temp
< temp_limits
[i
])
100 /* Use hysteresis before lowering speed again */
101 for (i
= min_speed
; i
< ARRAY_SIZE(temp_limits
); i
++) {
102 if (temp
<= (temp_limits
[i
] - hysteresis
))
108 if (fan
->last_speed
<= 0 && speed
)
109 speed
= MAX_SPEED
; /* kick start motor */
112 gpd_pocket_fan_set_speed(fan
, speed
);
114 /* When mostly idle (low temp/speed), slow down the poll interval. */
115 queue_delayed_work(system_wq
, &fan
->work
,
116 msecs_to_jiffies(4000 / (speed
+ 1)));
119 static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data
*fan
)
121 fan
->last_speed
= -1;
122 mod_delayed_work(system_wq
, &fan
->work
, 0);
125 static int gpd_pocket_fan_probe(struct platform_device
*pdev
)
127 struct gpd_pocket_fan_data
*fan
;
130 for (i
= 0; i
< ARRAY_SIZE(temp_limits
); i
++) {
131 if (temp_limits
[i
] < 20000 || temp_limits
[i
] > 90000) {
132 dev_err(&pdev
->dev
, "Invalid temp-limit %d (must be between 20000 and 90000)\n",
134 temp_limits
[0] = TEMP_LIMIT0_DEFAULT
;
135 temp_limits
[1] = TEMP_LIMIT1_DEFAULT
;
136 temp_limits
[2] = TEMP_LIMIT2_DEFAULT
;
140 if (hysteresis
< 1000 || hysteresis
> 10000) {
141 dev_err(&pdev
->dev
, "Invalid hysteresis %d (must be between 1000 and 10000)\n",
143 hysteresis
= HYSTERESIS_DEFAULT
;
145 if (speed_on_ac
< 0 || speed_on_ac
> MAX_SPEED
) {
146 dev_err(&pdev
->dev
, "Invalid speed_on_ac %d (must be between 0 and 3)\n",
148 speed_on_ac
= SPEED_ON_AC_DEFAULT
;
151 fan
= devm_kzalloc(&pdev
->dev
, sizeof(*fan
), GFP_KERNEL
);
155 fan
->dev
= &pdev
->dev
;
156 ret
= devm_delayed_work_autocancel(&pdev
->dev
, &fan
->work
,
157 gpd_pocket_fan_worker
);
161 /* Note this returns a "weak" reference which we don't need to free */
162 fan
->dts0
= thermal_zone_get_zone_by_name("soc_dts0");
163 if (IS_ERR(fan
->dts0
))
164 return -EPROBE_DEFER
;
166 fan
->dts1
= thermal_zone_get_zone_by_name("soc_dts1");
167 if (IS_ERR(fan
->dts1
))
168 return -EPROBE_DEFER
;
170 fan
->gpio0
= devm_gpiod_get_index(fan
->dev
, NULL
, 0, GPIOD_ASIS
);
171 if (IS_ERR(fan
->gpio0
))
172 return PTR_ERR(fan
->gpio0
);
174 fan
->gpio1
= devm_gpiod_get_index(fan
->dev
, NULL
, 1, GPIOD_ASIS
);
175 if (IS_ERR(fan
->gpio1
))
176 return PTR_ERR(fan
->gpio1
);
178 gpd_pocket_fan_force_update(fan
);
180 platform_set_drvdata(pdev
, fan
);
184 #ifdef CONFIG_PM_SLEEP
185 static int gpd_pocket_fan_suspend(struct device
*dev
)
187 struct gpd_pocket_fan_data
*fan
= dev_get_drvdata(dev
);
189 cancel_delayed_work_sync(&fan
->work
);
190 gpd_pocket_fan_set_speed(fan
, gpd_pocket_fan_min_speed());
194 static int gpd_pocket_fan_resume(struct device
*dev
)
196 struct gpd_pocket_fan_data
*fan
= dev_get_drvdata(dev
);
198 gpd_pocket_fan_force_update(fan
);
202 static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops
,
203 gpd_pocket_fan_suspend
,
204 gpd_pocket_fan_resume
);
206 static struct acpi_device_id gpd_pocket_fan_acpi_match
[] = {
210 MODULE_DEVICE_TABLE(acpi
, gpd_pocket_fan_acpi_match
);
212 static struct platform_driver gpd_pocket_fan_driver
= {
213 .probe
= gpd_pocket_fan_probe
,
215 .name
= "gpd_pocket_fan",
216 .acpi_match_table
= gpd_pocket_fan_acpi_match
,
217 .pm
= &gpd_pocket_fan_pm_ops
,
221 module_platform_driver(gpd_pocket_fan_driver
);
222 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
223 MODULE_DESCRIPTION("GPD pocket fan driver");
224 MODULE_LICENSE("GPL");