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/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
12 #include <linux/platform_device.h>
13 #include <linux/power_supply.h>
14 #include <linux/thermal.h>
15 #include <linux/workqueue.h>
19 #define TEMP_LIMIT0_DEFAULT 55000
20 #define TEMP_LIMIT1_DEFAULT 60000
21 #define TEMP_LIMIT2_DEFAULT 65000
23 #define HYSTERESIS_DEFAULT 3000
25 #define SPEED_ON_AC_DEFAULT 2
27 static int temp_limits
[3] = {
28 TEMP_LIMIT0_DEFAULT
, TEMP_LIMIT1_DEFAULT
, TEMP_LIMIT2_DEFAULT
,
30 module_param_array(temp_limits
, int, NULL
, 0444);
31 MODULE_PARM_DESC(temp_limits
,
32 "Millicelsius values above which the fan speed increases");
34 static int hysteresis
= HYSTERESIS_DEFAULT
;
35 module_param(hysteresis
, int, 0444);
36 MODULE_PARM_DESC(hysteresis
,
37 "Hysteresis in millicelsius before lowering the fan speed");
39 static int speed_on_ac
= SPEED_ON_AC_DEFAULT
;
40 module_param(speed_on_ac
, int, 0444);
41 MODULE_PARM_DESC(speed_on_ac
,
42 "minimum fan speed to allow when system is powered by AC");
44 struct gpd_pocket_fan_data
{
46 struct thermal_zone_device
*dts0
;
47 struct thermal_zone_device
*dts1
;
48 struct gpio_desc
*gpio0
;
49 struct gpio_desc
*gpio1
;
50 struct delayed_work work
;
54 static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data
*fan
, int speed
)
56 if (speed
== fan
->last_speed
)
59 gpiod_direction_output(fan
->gpio0
, !!(speed
& 1));
60 gpiod_direction_output(fan
->gpio1
, !!(speed
& 2));
62 fan
->last_speed
= speed
;
65 static int gpd_pocket_fan_min_speed(void)
67 if (power_supply_is_system_supplied())
73 static void gpd_pocket_fan_worker(struct work_struct
*work
)
75 struct gpd_pocket_fan_data
*fan
=
76 container_of(work
, struct gpd_pocket_fan_data
, work
.work
);
77 int t0
, t1
, temp
, speed
, min_speed
, i
;
79 if (thermal_zone_get_temp(fan
->dts0
, &t0
) ||
80 thermal_zone_get_temp(fan
->dts1
, &t1
)) {
81 dev_warn(fan
->dev
, "Error getting temperature\n");
88 speed
= fan
->last_speed
;
89 min_speed
= gpd_pocket_fan_min_speed();
91 /* Determine minimum speed */
92 for (i
= min_speed
; i
< ARRAY_SIZE(temp_limits
); i
++) {
93 if (temp
< temp_limits
[i
])
99 /* Use hysteresis before lowering speed again */
100 for (i
= min_speed
; i
< ARRAY_SIZE(temp_limits
); i
++) {
101 if (temp
<= (temp_limits
[i
] - hysteresis
))
107 if (fan
->last_speed
<= 0 && speed
)
108 speed
= MAX_SPEED
; /* kick start motor */
111 gpd_pocket_fan_set_speed(fan
, speed
);
113 /* When mostly idle (low temp/speed), slow down the poll interval. */
114 queue_delayed_work(system_wq
, &fan
->work
,
115 msecs_to_jiffies(4000 / (speed
+ 1)));
118 static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data
*fan
)
120 fan
->last_speed
= -1;
121 mod_delayed_work(system_wq
, &fan
->work
, 0);
124 static int gpd_pocket_fan_probe(struct platform_device
*pdev
)
126 struct gpd_pocket_fan_data
*fan
;
129 for (i
= 0; i
< ARRAY_SIZE(temp_limits
); i
++) {
130 if (temp_limits
[i
] < 20000 || temp_limits
[i
] > 90000) {
131 dev_err(&pdev
->dev
, "Invalid temp-limit %d (must be between 40000 and 70000)\n",
133 temp_limits
[0] = TEMP_LIMIT0_DEFAULT
;
134 temp_limits
[1] = TEMP_LIMIT1_DEFAULT
;
135 temp_limits
[2] = TEMP_LIMIT2_DEFAULT
;
139 if (hysteresis
< 1000 || hysteresis
> 10000) {
140 dev_err(&pdev
->dev
, "Invalid hysteresis %d (must be between 1000 and 10000)\n",
142 hysteresis
= HYSTERESIS_DEFAULT
;
144 if (speed_on_ac
< 0 || speed_on_ac
> MAX_SPEED
) {
145 dev_err(&pdev
->dev
, "Invalid speed_on_ac %d (must be between 0 and 3)\n",
147 speed_on_ac
= SPEED_ON_AC_DEFAULT
;
150 fan
= devm_kzalloc(&pdev
->dev
, sizeof(*fan
), GFP_KERNEL
);
154 fan
->dev
= &pdev
->dev
;
155 INIT_DELAYED_WORK(&fan
->work
, gpd_pocket_fan_worker
);
157 /* Note this returns a "weak" reference which we don't need to free */
158 fan
->dts0
= thermal_zone_get_zone_by_name("soc_dts0");
159 if (IS_ERR(fan
->dts0
))
160 return -EPROBE_DEFER
;
162 fan
->dts1
= thermal_zone_get_zone_by_name("soc_dts1");
163 if (IS_ERR(fan
->dts1
))
164 return -EPROBE_DEFER
;
166 fan
->gpio0
= devm_gpiod_get_index(fan
->dev
, NULL
, 0, GPIOD_ASIS
);
167 if (IS_ERR(fan
->gpio0
))
168 return PTR_ERR(fan
->gpio0
);
170 fan
->gpio1
= devm_gpiod_get_index(fan
->dev
, NULL
, 1, GPIOD_ASIS
);
171 if (IS_ERR(fan
->gpio1
))
172 return PTR_ERR(fan
->gpio1
);
174 gpd_pocket_fan_force_update(fan
);
176 platform_set_drvdata(pdev
, fan
);
180 static int gpd_pocket_fan_remove(struct platform_device
*pdev
)
182 struct gpd_pocket_fan_data
*fan
= platform_get_drvdata(pdev
);
184 cancel_delayed_work_sync(&fan
->work
);
188 #ifdef CONFIG_PM_SLEEP
189 static int gpd_pocket_fan_suspend(struct device
*dev
)
191 struct gpd_pocket_fan_data
*fan
= dev_get_drvdata(dev
);
193 cancel_delayed_work_sync(&fan
->work
);
194 gpd_pocket_fan_set_speed(fan
, gpd_pocket_fan_min_speed());
198 static int gpd_pocket_fan_resume(struct device
*dev
)
200 struct gpd_pocket_fan_data
*fan
= dev_get_drvdata(dev
);
202 gpd_pocket_fan_force_update(fan
);
206 static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops
,
207 gpd_pocket_fan_suspend
,
208 gpd_pocket_fan_resume
);
210 static struct acpi_device_id gpd_pocket_fan_acpi_match
[] = {
214 MODULE_DEVICE_TABLE(acpi
, gpd_pocket_fan_acpi_match
);
216 static struct platform_driver gpd_pocket_fan_driver
= {
217 .probe
= gpd_pocket_fan_probe
,
218 .remove
= gpd_pocket_fan_remove
,
220 .name
= "gpd_pocket_fan",
221 .acpi_match_table
= gpd_pocket_fan_acpi_match
,
222 .pm
= &gpd_pocket_fan_pm_ops
,
226 module_platform_driver(gpd_pocket_fan_driver
);
227 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
228 MODULE_DESCRIPTION("GPD pocket fan driver");
229 MODULE_LICENSE("GPL");