gpio-restart.c (3678B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Toggles a GPIO pin to restart a device 4 * 5 * Copyright (C) 2014 Google, Inc. 6 * 7 * Based on the gpio-poweroff driver. 8 */ 9#include <linux/reboot.h> 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/delay.h> 13#include <linux/platform_device.h> 14#include <linux/gpio/consumer.h> 15#include <linux/of_platform.h> 16#include <linux/module.h> 17 18struct gpio_restart { 19 struct gpio_desc *reset_gpio; 20 struct notifier_block restart_handler; 21 u32 active_delay_ms; 22 u32 inactive_delay_ms; 23 u32 wait_delay_ms; 24}; 25 26static int gpio_restart_notify(struct notifier_block *this, 27 unsigned long mode, void *cmd) 28{ 29 struct gpio_restart *gpio_restart = 30 container_of(this, struct gpio_restart, restart_handler); 31 32 /* drive it active, also inactive->active edge */ 33 gpiod_direction_output(gpio_restart->reset_gpio, 1); 34 mdelay(gpio_restart->active_delay_ms); 35 36 /* drive inactive, also active->inactive edge */ 37 gpiod_set_value(gpio_restart->reset_gpio, 0); 38 mdelay(gpio_restart->inactive_delay_ms); 39 40 /* drive it active, also inactive->active edge */ 41 gpiod_set_value(gpio_restart->reset_gpio, 1); 42 43 /* give it some time */ 44 mdelay(gpio_restart->wait_delay_ms); 45 46 WARN_ON(1); 47 48 return NOTIFY_DONE; 49} 50 51static int gpio_restart_probe(struct platform_device *pdev) 52{ 53 struct gpio_restart *gpio_restart; 54 bool open_source = false; 55 u32 property; 56 int ret; 57 58 gpio_restart = devm_kzalloc(&pdev->dev, sizeof(*gpio_restart), 59 GFP_KERNEL); 60 if (!gpio_restart) 61 return -ENOMEM; 62 63 open_source = of_property_read_bool(pdev->dev.of_node, "open-source"); 64 65 gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL, 66 open_source ? GPIOD_IN : GPIOD_OUT_LOW); 67 ret = PTR_ERR_OR_ZERO(gpio_restart->reset_gpio); 68 if (ret) { 69 if (ret != -EPROBE_DEFER) 70 dev_err(&pdev->dev, "Could not get reset GPIO\n"); 71 return ret; 72 } 73 74 gpio_restart->restart_handler.notifier_call = gpio_restart_notify; 75 gpio_restart->restart_handler.priority = 129; 76 gpio_restart->active_delay_ms = 100; 77 gpio_restart->inactive_delay_ms = 100; 78 gpio_restart->wait_delay_ms = 3000; 79 80 ret = of_property_read_u32(pdev->dev.of_node, "priority", &property); 81 if (!ret) { 82 if (property > 255) 83 dev_err(&pdev->dev, "Invalid priority property: %u\n", 84 property); 85 else 86 gpio_restart->restart_handler.priority = property; 87 } 88 89 of_property_read_u32(pdev->dev.of_node, "active-delay", 90 &gpio_restart->active_delay_ms); 91 of_property_read_u32(pdev->dev.of_node, "inactive-delay", 92 &gpio_restart->inactive_delay_ms); 93 of_property_read_u32(pdev->dev.of_node, "wait-delay", 94 &gpio_restart->wait_delay_ms); 95 96 platform_set_drvdata(pdev, gpio_restart); 97 98 ret = register_restart_handler(&gpio_restart->restart_handler); 99 if (ret) { 100 dev_err(&pdev->dev, "%s: cannot register restart handler, %d\n", 101 __func__, ret); 102 return -ENODEV; 103 } 104 105 return 0; 106} 107 108static int gpio_restart_remove(struct platform_device *pdev) 109{ 110 struct gpio_restart *gpio_restart = platform_get_drvdata(pdev); 111 int ret; 112 113 ret = unregister_restart_handler(&gpio_restart->restart_handler); 114 if (ret) { 115 dev_err(&pdev->dev, 116 "%s: cannot unregister restart handler, %d\n", 117 __func__, ret); 118 return -ENODEV; 119 } 120 121 return 0; 122} 123 124static const struct of_device_id of_gpio_restart_match[] = { 125 { .compatible = "gpio-restart", }, 126 {}, 127}; 128 129static struct platform_driver gpio_restart_driver = { 130 .probe = gpio_restart_probe, 131 .remove = gpio_restart_remove, 132 .driver = { 133 .name = "restart-gpio", 134 .of_match_table = of_gpio_restart_match, 135 }, 136}; 137 138module_platform_driver(gpio_restart_driver); 139 140MODULE_AUTHOR("David Riley <davidriley@chromium.org>"); 141MODULE_DESCRIPTION("GPIO restart driver"); 142MODULE_LICENSE("GPL");