xref: /linux/drivers/power/reset/spacemit-p1-reboot.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2025 by Aurelien Jarno
4  */
5 
6 #include <linux/bits.h>
7 #include <linux/mod_devicetable.h>
8 #include <linux/platform_device.h>
9 #include <linux/regmap.h>
10 #include <linux/reboot.h>
11 
12 /* Power Control Register 2 */
13 #define PWR_CTRL2		0x7e
14 #define PWR_CTRL2_SHUTDOWN	BIT(2)	/* Shutdown request */
15 #define PWR_CTRL2_RST		BIT(1)	/* Reset request */
16 
17 static int spacemit_p1_pwroff_handler(struct sys_off_data *data)
18 {
19 	struct regmap *regmap = data->cb_data;
20 	int ret;
21 
22 	/* Put the PMIC into shutdown state */
23 	ret = regmap_set_bits(regmap, PWR_CTRL2, PWR_CTRL2_SHUTDOWN);
24 	if (ret) {
25 		dev_err(data->dev, "shutdown failed: %d\n", ret);
26 		return notifier_from_errno(ret);
27 	}
28 
29 	return NOTIFY_DONE;
30 }
31 
32 static int spacemit_p1_restart_handler(struct sys_off_data *data)
33 {
34 	struct regmap *regmap = data->cb_data;
35 	int ret;
36 
37 	/* Put the PMIC into reset state */
38 	ret = regmap_set_bits(regmap, PWR_CTRL2, PWR_CTRL2_RST);
39 	if (ret) {
40 		dev_err(data->dev, "restart failed: %d\n", ret);
41 		return notifier_from_errno(ret);
42 	}
43 
44 	return NOTIFY_DONE;
45 }
46 
47 static int spacemit_p1_reboot_probe(struct platform_device *pdev)
48 {
49 	struct device *dev = &pdev->dev;
50 	struct regmap *regmap;
51 	int ret;
52 
53 	regmap = dev_get_regmap(dev->parent, NULL);
54 	if (!regmap)
55 		return -ENODEV;
56 
57 	ret = devm_register_power_off_handler(dev, &spacemit_p1_pwroff_handler,
58 					      regmap);
59 	if (ret)
60 		return dev_err_probe(dev, ret,
61 				     "Failed to register power off handler\n");
62 
63 	ret = devm_register_restart_handler(dev, spacemit_p1_restart_handler,
64 					    regmap);
65 	if (ret)
66 		return dev_err_probe(dev, ret,
67 				     "Failed to register restart handler\n");
68 
69 	return 0;
70 }
71 
72 static const struct platform_device_id spacemit_p1_reboot_id_table[] = {
73 	{ "spacemit-p1-reboot", },
74 	{ /* sentinel */ },
75 };
76 MODULE_DEVICE_TABLE(platform, spacemit_p1_reboot_id_table);
77 
78 static struct platform_driver spacemit_p1_reboot_driver = {
79 	.driver = {
80 		.name = "spacemit-p1-reboot",
81 	},
82 	.probe = spacemit_p1_reboot_probe,
83 	.id_table = spacemit_p1_reboot_id_table,
84 };
85 module_platform_driver(spacemit_p1_reboot_driver);
86 
87 MODULE_DESCRIPTION("SpacemiT P1 reboot/poweroff driver");
88 MODULE_LICENSE("GPL");
89