diff options
author | Feng Kan <fkan@apm.com> | 2014-09-30 19:25:03 -0400 |
---|---|---|
committer | Sebastian Reichel <sre@kernel.org> | 2014-09-30 22:21:05 -0400 |
commit | 09fb07bcaf529a21612fbebd1297d8c5dd1abf1b (patch) | |
tree | 3b256a21203971a136a5503b000864ee87316928 | |
parent | a3c0c3e79066c78b890c078998c8c6bd577f1d21 (diff) |
power: reset: Add generic SYSCON register mapped reset
Add a generic SYSCON register mapped reset mechanism.
Signed-off-by: Feng Kan <fkan@apm.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
-rw-r--r-- | drivers/power/reset/Kconfig | 5 | ||||
-rw-r--r-- | drivers/power/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/reset/syscon-reboot.c | 96 |
3 files changed, 102 insertions, 0 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index a178e9c50a20..addb26afae5a 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig | |||
@@ -118,3 +118,8 @@ config POWER_RESET_KEYSTONE | |||
118 | help | 118 | help |
119 | Reboot support for the KEYSTONE SoCs. | 119 | Reboot support for the KEYSTONE SoCs. |
120 | 120 | ||
121 | config POWER_RESET_SYSCON | ||
122 | bool "Generic SYSCON regmap reset driver" | ||
123 | depends on POWER_RESET && MFD_SYSCON && OF | ||
124 | help | ||
125 | Reboot support for generic SYSCON mapped register reset. | ||
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index ab8cd348a099..61ead2773331 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile | |||
@@ -13,3 +13,4 @@ obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o | |||
13 | obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o | 13 | obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o |
14 | obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o | 14 | obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o |
15 | obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o | 15 | obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o |
16 | obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o | ||
diff --git a/drivers/power/reset/syscon-reboot.c b/drivers/power/reset/syscon-reboot.c new file mode 100644 index 000000000000..948e0ee32a4d --- /dev/null +++ b/drivers/power/reset/syscon-reboot.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Generic Syscon Reboot Driver | ||
3 | * | ||
4 | * Copyright (c) 2013, Applied Micro Circuits Corporation | ||
5 | * Author: Feng Kan <fkan@apm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation; either version 2 of | ||
10 | * the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/of_device.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/notifier.h> | ||
22 | #include <linux/mfd/syscon.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/reboot.h> | ||
25 | |||
26 | struct syscon_reboot_context { | ||
27 | struct regmap *map; | ||
28 | u32 offset; | ||
29 | u32 mask; | ||
30 | struct notifier_block restart_handler; | ||
31 | }; | ||
32 | |||
33 | static struct syscon_reboot_context *syscon_reboot_ctx; | ||
34 | |||
35 | static int syscon_restart_handle(struct notifier_block *this, | ||
36 | unsigned long mode, void *cmd) | ||
37 | { | ||
38 | struct syscon_reboot_context *ctx = syscon_reboot_ctx; | ||
39 | unsigned long timeout; | ||
40 | |||
41 | /* Issue the reboot */ | ||
42 | if (ctx->map) | ||
43 | regmap_write(ctx->map, ctx->offset, ctx->mask); | ||
44 | |||
45 | timeout = jiffies + HZ; | ||
46 | while (time_before(jiffies, timeout)) | ||
47 | cpu_relax(); | ||
48 | |||
49 | pr_emerg("Unable to restart system\n"); | ||
50 | return NOTIFY_DONE; | ||
51 | } | ||
52 | |||
53 | static int syscon_reboot_probe(struct platform_device *pdev) | ||
54 | { | ||
55 | struct syscon_reboot_context *ctx; | ||
56 | struct device *dev = &pdev->dev; | ||
57 | int err; | ||
58 | |||
59 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | ||
60 | if (!ctx) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | ctx->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); | ||
64 | if (IS_ERR(ctx->map)) | ||
65 | return PTR_ERR(ctx->map); | ||
66 | |||
67 | if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset)) | ||
68 | return -EINVAL; | ||
69 | |||
70 | if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask)) | ||
71 | return -EINVAL; | ||
72 | |||
73 | ctx->restart_handler.notifier_call = syscon_restart_handle; | ||
74 | ctx->restart_handler.priority = 128; | ||
75 | err = register_restart_handler(&ctx->restart_handler); | ||
76 | if (err) | ||
77 | dev_err(dev, "can't register restart notifier (err=%d)\n", err); | ||
78 | |||
79 | syscon_reboot_ctx = ctx; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static struct of_device_id syscon_reboot_of_match[] = { | ||
85 | { .compatible = "syscon-reboot" }, | ||
86 | {} | ||
87 | }; | ||
88 | |||
89 | static struct platform_driver syscon_reboot_driver = { | ||
90 | .probe = syscon_reboot_probe, | ||
91 | .driver = { | ||
92 | .name = "syscon-reboot", | ||
93 | .of_match_table = syscon_reboot_of_match, | ||
94 | }, | ||
95 | }; | ||
96 | module_platform_driver(syscon_reboot_driver); | ||