1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Khadas MCU Controlled FAN driver
5 * Copyright (C) 2020 BayLibre SAS
6 * Author(s): Neil Armstrong <narmstrong@baylibre.com>
9 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/mfd/khadas-mcu.h>
13 #include <linux/regmap.h>
14 #include <linux/sysfs.h>
15 #include <linux/thermal.h>
19 struct khadas_mcu_fan_ctx
{
20 struct khadas_mcu
*mcu
;
22 struct thermal_cooling_device
*cdev
;
25 static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx
*ctx
,
30 ret
= regmap_write(ctx
->mcu
->regmap
, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG
,
40 static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device
*cdev
,
48 static int khadas_mcu_fan_get_cur_state(struct thermal_cooling_device
*cdev
,
51 struct khadas_mcu_fan_ctx
*ctx
= cdev
->devdata
;
59 khadas_mcu_fan_set_cur_state(struct thermal_cooling_device
*cdev
,
62 struct khadas_mcu_fan_ctx
*ctx
= cdev
->devdata
;
64 if (state
> MAX_LEVEL
)
67 if (state
== ctx
->level
)
70 return khadas_mcu_fan_set_level(ctx
, state
);
73 static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops
= {
74 .get_max_state
= khadas_mcu_fan_get_max_state
,
75 .get_cur_state
= khadas_mcu_fan_get_cur_state
,
76 .set_cur_state
= khadas_mcu_fan_set_cur_state
,
79 static int khadas_mcu_fan_probe(struct platform_device
*pdev
)
81 struct khadas_mcu
*mcu
= dev_get_drvdata(pdev
->dev
.parent
);
82 struct thermal_cooling_device
*cdev
;
83 struct device
*dev
= &pdev
->dev
;
84 struct khadas_mcu_fan_ctx
*ctx
;
87 ctx
= devm_kzalloc(dev
, sizeof(*ctx
), GFP_KERNEL
);
91 platform_set_drvdata(pdev
, ctx
);
93 cdev
= devm_thermal_of_cooling_device_register(dev
->parent
,
94 dev
->parent
->of_node
, "khadas-mcu-fan", ctx
,
95 &khadas_mcu_fan_cooling_ops
);
98 dev_err(dev
, "Failed to register khadas-mcu-fan as cooling device: %d\n",
107 static void khadas_mcu_fan_shutdown(struct platform_device
*pdev
)
109 struct khadas_mcu_fan_ctx
*ctx
= platform_get_drvdata(pdev
);
111 khadas_mcu_fan_set_level(ctx
, 0);
114 #ifdef CONFIG_PM_SLEEP
115 static int khadas_mcu_fan_suspend(struct device
*dev
)
117 struct khadas_mcu_fan_ctx
*ctx
= dev_get_drvdata(dev
);
118 unsigned int level_save
= ctx
->level
;
121 ret
= khadas_mcu_fan_set_level(ctx
, 0);
125 ctx
->level
= level_save
;
130 static int khadas_mcu_fan_resume(struct device
*dev
)
132 struct khadas_mcu_fan_ctx
*ctx
= dev_get_drvdata(dev
);
134 return khadas_mcu_fan_set_level(ctx
, ctx
->level
);
138 static SIMPLE_DEV_PM_OPS(khadas_mcu_fan_pm
, khadas_mcu_fan_suspend
,
139 khadas_mcu_fan_resume
);
141 static const struct platform_device_id khadas_mcu_fan_id_table
[] = {
142 { .name
= "khadas-mcu-fan-ctrl", },
145 MODULE_DEVICE_TABLE(platform
, khadas_mcu_fan_id_table
);
147 static struct platform_driver khadas_mcu_fan_driver
= {
148 .probe
= khadas_mcu_fan_probe
,
149 .shutdown
= khadas_mcu_fan_shutdown
,
151 .name
= "khadas-mcu-fan-ctrl",
152 .pm
= &khadas_mcu_fan_pm
,
154 .id_table
= khadas_mcu_fan_id_table
,
157 module_platform_driver(khadas_mcu_fan_driver
);
159 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
160 MODULE_DESCRIPTION("Khadas MCU FAN driver");
161 MODULE_LICENSE("GPL");