aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2014-05-06 22:44:20 -0400
committerMaxime Ripard <maxime.ripard@free-electrons.com>2014-05-23 04:40:34 -0400
commit1be7f5520a3885747174008d2905ae551f74ea78 (patch)
tree1bf23efdb1f40c7fd89aed19b833abc812d474f8 /drivers/power
parentcd90f0cf4454861a4f87bdfdcf01e8b98cc94869 (diff)
power: reset: Add Allwinner A31 reset code
That code used to be in the machine code, but it's more fit here with other restart hooks. That will allow to cleanup the machine directory, while waiting for a proper watchdog driver for the A31. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/reset/Kconfig7
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/sun6i-reboot.c85
3 files changed, 93 insertions, 0 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index fa0e4e057b99..67aeb6ec08f9 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -43,6 +43,13 @@ config POWER_RESET_RESTART
43 Instead they restart, and u-boot holds the SoC until the 43 Instead they restart, and u-boot holds the SoC until the
44 user presses a key. u-boot then boots into Linux. 44 user presses a key. u-boot then boots into Linux.
45 45
46config POWER_RESET_SUN6I
47 bool "Allwinner A31 SoC reset driver"
48 depends on ARCH_SUNXI
49 depends on POWER_RESET
50 help
51 Reboot support for the Allwinner A31 SoCs.
52
46config POWER_RESET_VEXPRESS 53config POWER_RESET_VEXPRESS
47 bool "ARM Versatile Express power-off and reset driver" 54 bool "ARM Versatile Express power-off and reset driver"
48 depends on ARM || ARM64 55 depends on ARM || ARM64
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index a5b4a77d1a41..950fdc011c7a 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
3obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o 3obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
4obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o 4obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
5obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o 5obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
6obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o
6obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o 7obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
7obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o 8obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
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
31static void __iomem *wdt_base;
32
33static 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
60static 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
73static struct of_device_id sun6i_reboot_of_match[] = {
74 { .compatible = "allwinner,sun6i-a31-wdt" },
75 {}
76};
77
78static 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};
85module_platform_driver(sun6i_reboot_driver);