summaryrefslogtreecommitdiffstats
path: root/drivers/power/reset/gpio-restart.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/reset/gpio-restart.c')
-rw-r--r--drivers/power/reset/gpio-restart.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c
new file mode 100644
index 0000000000..ed2748f910
--- /dev/null
+++ b/drivers/power/reset/gpio-restart.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Toggles a GPIO pin to restart a device
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Based on the gpio-poweroff driver.
+ */
+#include <common.h>
+#include <driver.h>
+#include <restart.h>
+#include <linux/gpio/consumer.h>
+
+struct gpio_restart {
+ struct gpio_desc *reset_gpio;
+ struct restart_handler restart_handler;
+ u32 active_delay_ms;
+ u32 inactive_delay_ms;
+ u32 wait_delay_ms;
+};
+
+static void __noreturn gpio_restart_handle(struct restart_handler *this)
+{
+ struct gpio_restart *gpio_restart =
+ container_of(this, struct gpio_restart, restart_handler);
+
+ /* drive it active, also inactive->active edge */
+ gpiod_direction_output(gpio_restart->reset_gpio, true);
+ mdelay(gpio_restart->active_delay_ms);
+
+ /* drive inactive, also active->inactive edge */
+ gpiod_direction_output(gpio_restart->reset_gpio, false);
+ mdelay(gpio_restart->inactive_delay_ms);
+
+ /* drive it active, also inactive->active edge */
+ gpiod_direction_output(gpio_restart->reset_gpio, true);
+
+ /* give it some time */
+ mdelay(gpio_restart->wait_delay_ms);
+
+ mdelay(1000);
+
+ panic("Unable to restart system\n");
+}
+
+static int gpio_restart_probe(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct gpio_restart *gpio_restart;
+ struct gpio_desc *gpiod;
+ bool open_source = false;
+ u32 property;
+ int ret;
+
+ gpio_restart = xzalloc(sizeof(*gpio_restart));
+
+ open_source = of_property_read_bool(np, "open-source");
+
+ gpiod = gpiod_get(dev, NULL, open_source ? GPIOD_IN : GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod))
+ return dev_errp_probe(dev, gpiod, "Could not get reset GPIO\n");
+
+ gpio_restart->reset_gpio = gpiod;
+ gpio_restart->restart_handler.restart = gpio_restart_handle;
+ gpio_restart->restart_handler.name = "gpio-restart";
+ gpio_restart->restart_handler.priority = 129;
+ gpio_restart->active_delay_ms = 100;
+ gpio_restart->inactive_delay_ms = 100;
+ gpio_restart->wait_delay_ms = 3000;
+
+ ret = of_property_read_u32(dev->of_node, "priority", &property);
+ if (!ret)
+ gpio_restart->restart_handler.priority = property;
+
+ of_property_read_u32(np, "active-delay", &gpio_restart->active_delay_ms);
+ of_property_read_u32(np, "inactive-delay", &gpio_restart->inactive_delay_ms);
+ of_property_read_u32(np, "wait-delay", &gpio_restart->wait_delay_ms);
+
+ return restart_handler_register(&gpio_restart->restart_handler);
+}
+
+static const struct of_device_id of_gpio_restart_match[] = {
+ { .compatible = "gpio-restart", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_gpio_restart_match);
+
+static struct driver gpio_restart_driver = {
+ .name = "restart-gpio",
+ .of_compatible = of_gpio_restart_match,
+ .probe = gpio_restart_probe,
+};
+device_platform_driver(gpio_restart_driver);
+
+MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
+MODULE_DESCRIPTION("GPIO restart driver");
+MODULE_LICENSE("GPL");