1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Force-disables a regulator to power down a device |
4 | * |
5 | * Michael Klein <michael@fossekall.de> |
6 | * |
7 | * Copyright (C) 2020 Michael Klein |
8 | * |
9 | * Based on the gpio-poweroff driver. |
10 | */ |
11 | #include <linux/delay.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/pm.h> |
16 | #include <linux/reboot.h> |
17 | #include <linux/regulator/consumer.h> |
18 | |
19 | #define TIMEOUT_MS 3000 |
20 | |
21 | static int regulator_poweroff_do_poweroff(struct sys_off_data *data) |
22 | { |
23 | struct regulator *cpu_regulator = data->cb_data; |
24 | |
25 | if (cpu_regulator && regulator_is_enabled(regulator: cpu_regulator)) |
26 | regulator_force_disable(regulator: cpu_regulator); |
27 | |
28 | /* give it some time */ |
29 | mdelay(TIMEOUT_MS); |
30 | |
31 | WARN_ON(1); |
32 | |
33 | return NOTIFY_DONE; |
34 | } |
35 | |
36 | static int regulator_poweroff_probe(struct platform_device *pdev) |
37 | { |
38 | struct regulator *cpu_regulator; |
39 | |
40 | cpu_regulator = devm_regulator_get(dev: &pdev->dev, id: "cpu" ); |
41 | if (IS_ERR(ptr: cpu_regulator)) |
42 | return PTR_ERR(ptr: cpu_regulator); |
43 | |
44 | /* Set this handler to low priority to not override an existing handler */ |
45 | return devm_register_sys_off_handler(dev: &pdev->dev, |
46 | mode: SYS_OFF_MODE_POWER_OFF, |
47 | SYS_OFF_PRIO_LOW, |
48 | callback: regulator_poweroff_do_poweroff, |
49 | cb_data: cpu_regulator); |
50 | } |
51 | |
52 | static const struct of_device_id of_regulator_poweroff_match[] = { |
53 | { .compatible = "regulator-poweroff" , }, |
54 | {}, |
55 | }; |
56 | MODULE_DEVICE_TABLE(of, of_regulator_poweroff_match); |
57 | |
58 | static struct platform_driver regulator_poweroff_driver = { |
59 | .probe = regulator_poweroff_probe, |
60 | .driver = { |
61 | .name = "poweroff-regulator" , |
62 | .of_match_table = of_regulator_poweroff_match, |
63 | }, |
64 | }; |
65 | |
66 | module_platform_driver(regulator_poweroff_driver); |
67 | |
68 | MODULE_AUTHOR("Michael Klein <michael@fossekall.de>" ); |
69 | MODULE_DESCRIPTION("Regulator poweroff driver" ); |
70 | MODULE_ALIAS("platform:poweroff-regulator" ); |
71 | |