Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Toggles a GPIO pin to restart a device
0004  *
0005  * Copyright (C) 2014 Google, Inc.
0006  *
0007  * Based on the gpio-poweroff driver.
0008  */
0009 #include <linux/reboot.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/delay.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/gpio/consumer.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/module.h>
0017 
0018 struct gpio_restart {
0019     struct gpio_desc *reset_gpio;
0020     struct notifier_block restart_handler;
0021     u32 active_delay_ms;
0022     u32 inactive_delay_ms;
0023     u32 wait_delay_ms;
0024 };
0025 
0026 static int gpio_restart_notify(struct notifier_block *this,
0027                 unsigned long mode, void *cmd)
0028 {
0029     struct gpio_restart *gpio_restart =
0030         container_of(this, struct gpio_restart, restart_handler);
0031 
0032     /* drive it active, also inactive->active edge */
0033     gpiod_direction_output(gpio_restart->reset_gpio, 1);
0034     mdelay(gpio_restart->active_delay_ms);
0035 
0036     /* drive inactive, also active->inactive edge */
0037     gpiod_set_value(gpio_restart->reset_gpio, 0);
0038     mdelay(gpio_restart->inactive_delay_ms);
0039 
0040     /* drive it active, also inactive->active edge */
0041     gpiod_set_value(gpio_restart->reset_gpio, 1);
0042 
0043     /* give it some time */
0044     mdelay(gpio_restart->wait_delay_ms);
0045 
0046     WARN_ON(1);
0047 
0048     return NOTIFY_DONE;
0049 }
0050 
0051 static int gpio_restart_probe(struct platform_device *pdev)
0052 {
0053     struct gpio_restart *gpio_restart;
0054     bool open_source = false;
0055     u32 property;
0056     int ret;
0057 
0058     gpio_restart = devm_kzalloc(&pdev->dev, sizeof(*gpio_restart),
0059             GFP_KERNEL);
0060     if (!gpio_restart)
0061         return -ENOMEM;
0062 
0063     open_source = of_property_read_bool(pdev->dev.of_node, "open-source");
0064 
0065     gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL,
0066             open_source ? GPIOD_IN : GPIOD_OUT_LOW);
0067     ret = PTR_ERR_OR_ZERO(gpio_restart->reset_gpio);
0068     if (ret) {
0069         if (ret != -EPROBE_DEFER)
0070             dev_err(&pdev->dev, "Could not get reset GPIO\n");
0071         return ret;
0072     }
0073 
0074     gpio_restart->restart_handler.notifier_call = gpio_restart_notify;
0075     gpio_restart->restart_handler.priority = 129;
0076     gpio_restart->active_delay_ms = 100;
0077     gpio_restart->inactive_delay_ms = 100;
0078     gpio_restart->wait_delay_ms = 3000;
0079 
0080     ret = of_property_read_u32(pdev->dev.of_node, "priority", &property);
0081     if (!ret) {
0082         if (property > 255)
0083             dev_err(&pdev->dev, "Invalid priority property: %u\n",
0084                     property);
0085         else
0086             gpio_restart->restart_handler.priority = property;
0087     }
0088 
0089     of_property_read_u32(pdev->dev.of_node, "active-delay",
0090             &gpio_restart->active_delay_ms);
0091     of_property_read_u32(pdev->dev.of_node, "inactive-delay",
0092             &gpio_restart->inactive_delay_ms);
0093     of_property_read_u32(pdev->dev.of_node, "wait-delay",
0094             &gpio_restart->wait_delay_ms);
0095 
0096     platform_set_drvdata(pdev, gpio_restart);
0097 
0098     ret = register_restart_handler(&gpio_restart->restart_handler);
0099     if (ret) {
0100         dev_err(&pdev->dev, "%s: cannot register restart handler, %d\n",
0101                 __func__, ret);
0102         return -ENODEV;
0103     }
0104 
0105     return 0;
0106 }
0107 
0108 static int gpio_restart_remove(struct platform_device *pdev)
0109 {
0110     struct gpio_restart *gpio_restart = platform_get_drvdata(pdev);
0111     int ret;
0112 
0113     ret = unregister_restart_handler(&gpio_restart->restart_handler);
0114     if (ret) {
0115         dev_err(&pdev->dev,
0116                 "%s: cannot unregister restart handler, %d\n",
0117                 __func__, ret);
0118         return -ENODEV;
0119     }
0120 
0121     return 0;
0122 }
0123 
0124 static const struct of_device_id of_gpio_restart_match[] = {
0125     { .compatible = "gpio-restart", },
0126     {},
0127 };
0128 
0129 static struct platform_driver gpio_restart_driver = {
0130     .probe = gpio_restart_probe,
0131     .remove = gpio_restart_remove,
0132     .driver = {
0133         .name = "restart-gpio",
0134         .of_match_table = of_gpio_restart_match,
0135     },
0136 };
0137 
0138 module_platform_driver(gpio_restart_driver);
0139 
0140 MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
0141 MODULE_DESCRIPTION("GPIO restart driver");
0142 MODULE_LICENSE("GPL");