diff options
Diffstat (limited to 'drivers/power/reset/sun6i-reboot.c')
-rw-r--r-- | drivers/power/reset/sun6i-reboot.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/power/reset/sun6i-reboot.c b/drivers/power/reset/sun6i-reboot.c new file mode 100644 index 000000000000..af2cd7ff2fe8 --- /dev/null +++ b/drivers/power/reset/sun6i-reboot.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Allwinner A31 SoCs reset code | ||
3 | * | ||
4 | * Copyright (C) 2012-2014 Maxime Ripard | ||
5 | * | ||
6 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/reboot.h> | ||
19 | |||
20 | #include <asm/system_misc.h> | ||
21 | |||
22 | #define SUN6I_WATCHDOG1_IRQ_REG 0x00 | ||
23 | #define SUN6I_WATCHDOG1_CTRL_REG 0x10 | ||
24 | #define SUN6I_WATCHDOG1_CTRL_RESTART BIT(0) | ||
25 | #define SUN6I_WATCHDOG1_CONFIG_REG 0x14 | ||
26 | #define SUN6I_WATCHDOG1_CONFIG_RESTART BIT(0) | ||
27 | #define SUN6I_WATCHDOG1_CONFIG_IRQ BIT(1) | ||
28 | #define SUN6I_WATCHDOG1_MODE_REG 0x18 | ||
29 | #define SUN6I_WATCHDOG1_MODE_ENABLE BIT(0) | ||
30 | |||
31 | static void __iomem *wdt_base; | ||
32 | |||
33 | static void sun6i_wdt_restart(enum reboot_mode mode, const char *cmd) | ||
34 | { | ||
35 | if (!wdt_base) | ||
36 | return; | ||
37 | |||
38 | /* Disable interrupts */ | ||
39 | writel(0, wdt_base + SUN6I_WATCHDOG1_IRQ_REG); | ||
40 | |||
41 | /* We want to disable the IRQ and just reset the whole system */ | ||
42 | writel(SUN6I_WATCHDOG1_CONFIG_RESTART, | ||
43 | wdt_base + SUN6I_WATCHDOG1_CONFIG_REG); | ||
44 | |||
45 | /* Enable timer. The default and lowest interval value is 0.5s */ | ||
46 | writel(SUN6I_WATCHDOG1_MODE_ENABLE, | ||
47 | wdt_base + SUN6I_WATCHDOG1_MODE_REG); | ||
48 | |||
49 | /* Restart the watchdog. */ | ||
50 | writel(SUN6I_WATCHDOG1_CTRL_RESTART, | ||
51 | wdt_base + SUN6I_WATCHDOG1_CTRL_REG); | ||
52 | |||
53 | while (1) { | ||
54 | mdelay(5); | ||
55 | writel(SUN6I_WATCHDOG1_MODE_ENABLE, | ||
56 | wdt_base + SUN6I_WATCHDOG1_MODE_REG); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | static int sun6i_reboot_probe(struct platform_device *pdev) | ||
61 | { | ||
62 | wdt_base = of_iomap(pdev->dev.of_node, 0); | ||
63 | if (!wdt_base) { | ||
64 | WARN(1, "failed to map watchdog base address"); | ||
65 | return -ENODEV; | ||
66 | } | ||
67 | |||
68 | arm_pm_restart = sun6i_wdt_restart; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static struct of_device_id sun6i_reboot_of_match[] = { | ||
74 | { .compatible = "allwinner,sun6i-a31-wdt" }, | ||
75 | {} | ||
76 | }; | ||
77 | |||
78 | static struct platform_driver sun6i_reboot_driver = { | ||
79 | .probe = sun6i_reboot_probe, | ||
80 | .driver = { | ||
81 | .name = "sun6i-reboot", | ||
82 | .of_match_table = sun6i_reboot_of_match, | ||
83 | }, | ||
84 | }; | ||
85 | module_platform_driver(sun6i_reboot_driver); | ||