aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-restart.txt54
-rw-r--r--drivers/power/reset/Kconfig8
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/gpio-restart.c149
4 files changed, 212 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-restart.txt b/Documentation/devicetree/bindings/gpio/gpio-restart.txt
new file mode 100644
index 000000000000..af3701bc15c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-restart.txt
@@ -0,0 +1,54 @@
1Drive a GPIO line that can be used to restart the system from a restart
2handler.
3
4This binding supports level and edge triggered reset. At driver load
5time, the driver will request the given gpio line and install a restart
6handler. If the optional properties 'open-source' is not found, the GPIO line
7will be driven in the inactive state. Otherwise its not driven until
8the restart is initiated.
9
10When the system is restarted, the restart handler will be invoked in
11priority order. The gpio is configured as an output, and driven active,
12triggering a level triggered reset condition. This will also cause an
13inactive->active edge condition, triggering positive edge triggered
14reset. After a delay specified by active-delay, the GPIO is set to
15inactive, thus causing an active->inactive edge, triggering negative edge
16triggered reset. After a delay specified by inactive-delay, the GPIO
17is driven active again. After a delay specified by wait-delay, the
18restart handler completes allowing other restart handlers to be attempted.
19
20Required properties:
21- compatible : should be "gpio-restart".
22- gpios : The GPIO to set high/low, see "gpios property" in
23 Documentation/devicetree/bindings/gpio/gpio.txt. If the pin should be
24 low to reset the board set it to "Active Low", otherwise set
25 gpio to "Active High".
26
27Optional properties:
28- open-source : Treat the GPIO as being open source and defer driving
29 it to when the restart is initiated. If this optional property is not
30 specified, the GPIO is initialized as an output in its inactive state.
31- priority : A priority ranging from 0 to 255 (default 128) according to
32 the following guidelines:
33 0: Restart handler of last resort, with limited restart
34 capabilities
35 128: Default restart handler; use if no other restart handler is
36 expected to be available, and/or if restart functionality is
37 sufficient to restart the entire system
38 255: Highest priority restart handler, will preempt all other
39 restart handlers
40- active-delay: Delay (default 100) to wait after driving gpio active [ms]
41- inactive-delay: Delay (default 100) to wait after driving gpio inactive [ms]
42- wait-delay: Delay (default 3000) to wait after completing restart
43 sequence [ms]
44
45Examples:
46
47gpio-restart {
48 compatible = "gpio-restart";
49 gpios = <&gpio 4 0>;
50 priority = <128>;
51 active-delay = <100>;
52 inactive-delay = <100>;
53 wait-delay = <3000>;
54};
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 88603b6990ed..a178e9c50a20 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -39,6 +39,14 @@ config POWER_RESET_GPIO
39 If your board needs a GPIO high/low to power down, say Y and 39 If your board needs a GPIO high/low to power down, say Y and
40 create a binding in your devicetree. 40 create a binding in your devicetree.
41 41
42config POWER_RESET_GPIO_RESTART
43 bool "GPIO restart driver"
44 depends on OF_GPIO && POWER_RESET
45 help
46 This driver supports restarting your board via a GPIO line.
47 If your board needs a GPIO high/low to restart, say Y and
48 create a binding in your devicetree.
49
42config POWER_RESET_HISI 50config POWER_RESET_HISI
43 bool "Hisilicon power-off driver" 51 bool "Hisilicon power-off driver"
44 depends on POWER_RESET && ARCH_HISI 52 depends on POWER_RESET && ARCH_HISI
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 06f106b6cfc8..ab8cd348a099 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o
2obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o 2obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
3obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o 3obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
4obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o 4obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
5obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
5obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o 6obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
6obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o 7obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
7obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o 8obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c
new file mode 100644
index 000000000000..a76829b3f1cd
--- /dev/null
+++ b/drivers/power/reset/gpio-restart.c
@@ -0,0 +1,149 @@
1/*
2 * Toggles a GPIO pin to restart a device
3 *
4 * Copyright (C) 2014 Google, Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * Based on the gpio-poweroff driver.
16 */
17#include <linux/reboot.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/platform_device.h>
22#include <linux/gpio/consumer.h>
23#include <linux/of_platform.h>
24#include <linux/module.h>
25
26struct gpio_restart {
27 struct gpio_desc *reset_gpio;
28 struct notifier_block restart_handler;
29 u32 active_delay_ms;
30 u32 inactive_delay_ms;
31 u32 wait_delay_ms;
32};
33
34static int gpio_restart_notify(struct notifier_block *this,
35 unsigned long mode, void *cmd)
36{
37 struct gpio_restart *gpio_restart =
38 container_of(this, struct gpio_restart, restart_handler);
39
40 /* drive it active, also inactive->active edge */
41 gpiod_direction_output(gpio_restart->reset_gpio, 1);
42 mdelay(gpio_restart->active_delay_ms);
43
44 /* drive inactive, also active->inactive edge */
45 gpiod_set_value(gpio_restart->reset_gpio, 0);
46 mdelay(gpio_restart->inactive_delay_ms);
47
48 /* drive it active, also inactive->active edge */
49 gpiod_set_value(gpio_restart->reset_gpio, 1);
50
51 /* give it some time */
52 mdelay(gpio_restart->wait_delay_ms);
53
54 WARN_ON(1);
55
56 return NOTIFY_DONE;
57}
58
59static int gpio_restart_probe(struct platform_device *pdev)
60{
61 struct gpio_restart *gpio_restart;
62 bool open_source = false;
63 u32 property;
64 int ret;
65
66 gpio_restart = devm_kzalloc(&pdev->dev, sizeof(*gpio_restart),
67 GFP_KERNEL);
68 if (!gpio_restart)
69 return -ENOMEM;
70
71 open_source = of_property_read_bool(pdev->dev.of_node, "open-source");
72
73 gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL,
74 open_source ? GPIOD_IN : GPIOD_OUT_LOW);
75 if (IS_ERR(gpio_restart->reset_gpio)) {
76 dev_err(&pdev->dev, "Could net get reset GPIO\n");
77 return PTR_ERR(gpio_restart->reset_gpio);
78 }
79
80 gpio_restart->restart_handler.notifier_call = gpio_restart_notify;
81 gpio_restart->restart_handler.priority = 128;
82 gpio_restart->active_delay_ms = 100;
83 gpio_restart->inactive_delay_ms = 100;
84 gpio_restart->wait_delay_ms = 3000;
85
86 ret = of_property_read_u32(pdev->dev.of_node, "priority", &property);
87 if (!ret) {
88 if (property > 255)
89 dev_err(&pdev->dev, "Invalid priority property: %u\n",
90 property);
91 else
92 gpio_restart->restart_handler.priority = property;
93 }
94
95 of_property_read_u32(pdev->dev.of_node, "active-delay",
96 &gpio_restart->active_delay_ms);
97 of_property_read_u32(pdev->dev.of_node, "inactive-delay",
98 &gpio_restart->inactive_delay_ms);
99 of_property_read_u32(pdev->dev.of_node, "wait-delay",
100 &gpio_restart->wait_delay_ms);
101
102 platform_set_drvdata(pdev, gpio_restart);
103
104 ret = register_restart_handler(&gpio_restart->restart_handler);
105 if (ret) {
106 dev_err(&pdev->dev, "%s: cannot register restart handler, %d\n",
107 __func__, ret);
108 return -ENODEV;
109 }
110
111 return 0;
112}
113
114static int gpio_restart_remove(struct platform_device *pdev)
115{
116 struct gpio_restart *gpio_restart = platform_get_drvdata(pdev);
117 int ret;
118
119 ret = unregister_restart_handler(&gpio_restart->restart_handler);
120 if (ret) {
121 dev_err(&pdev->dev,
122 "%s: cannot unregister restart handler, %d\n",
123 __func__, ret);
124 return -ENODEV;
125 }
126
127 return 0;
128}
129
130static const struct of_device_id of_gpio_restart_match[] = {
131 { .compatible = "gpio-restart", },
132 {},
133};
134
135static struct platform_driver gpio_restart_driver = {
136 .probe = gpio_restart_probe,
137 .remove = gpio_restart_remove,
138 .driver = {
139 .name = "restart-gpio",
140 .owner = THIS_MODULE,
141 .of_match_table = of_gpio_restart_match,
142 },
143};
144
145module_platform_driver(gpio_restart_driver);
146
147MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
148MODULE_DESCRIPTION("GPIO restart driver");
149MODULE_LICENSE("GPL");