123 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Toggles a GPIO pin to restart a device4 *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/module.h>16#include <linux/of.h>17 18struct gpio_restart {19 struct gpio_desc *reset_gpio;20 u32 active_delay_ms;21 u32 inactive_delay_ms;22 u32 wait_delay_ms;23};24 25static int gpio_restart_notify(struct sys_off_data *data)26{27 struct gpio_restart *gpio_restart = data->cb_data;28 29 /* drive it active, also inactive->active edge */30 gpiod_direction_output(gpio_restart->reset_gpio, 1);31 mdelay(gpio_restart->active_delay_ms);32 33 /* drive inactive, also active->inactive edge */34 gpiod_set_value(gpio_restart->reset_gpio, 0);35 mdelay(gpio_restart->inactive_delay_ms);36 37 /* drive it active, also inactive->active edge */38 gpiod_set_value(gpio_restart->reset_gpio, 1);39 40 /* give it some time */41 mdelay(gpio_restart->wait_delay_ms);42 43 WARN_ON(1);44 45 return NOTIFY_DONE;46}47 48static int gpio_restart_probe(struct platform_device *pdev)49{50 struct gpio_restart *gpio_restart;51 bool open_source = false;52 int priority = 129;53 u32 property;54 int ret;55 56 gpio_restart = devm_kzalloc(&pdev->dev, sizeof(*gpio_restart),57 GFP_KERNEL);58 if (!gpio_restart)59 return -ENOMEM;60 61 open_source = of_property_read_bool(pdev->dev.of_node, "open-source");62 63 gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL,64 open_source ? GPIOD_IN : GPIOD_OUT_LOW);65 ret = PTR_ERR_OR_ZERO(gpio_restart->reset_gpio);66 if (ret) {67 if (ret != -EPROBE_DEFER)68 dev_err(&pdev->dev, "Could not get reset GPIO\n");69 return ret;70 }71 72 gpio_restart->active_delay_ms = 100;73 gpio_restart->inactive_delay_ms = 100;74 gpio_restart->wait_delay_ms = 3000;75 76 ret = of_property_read_u32(pdev->dev.of_node, "priority", &property);77 if (!ret) {78 if (property > 255)79 dev_err(&pdev->dev, "Invalid priority property: %u\n",80 property);81 else82 priority = property;83 }84 85 of_property_read_u32(pdev->dev.of_node, "active-delay",86 &gpio_restart->active_delay_ms);87 of_property_read_u32(pdev->dev.of_node, "inactive-delay",88 &gpio_restart->inactive_delay_ms);89 of_property_read_u32(pdev->dev.of_node, "wait-delay",90 &gpio_restart->wait_delay_ms);91 92 ret = devm_register_sys_off_handler(&pdev->dev,93 SYS_OFF_MODE_RESTART,94 priority,95 gpio_restart_notify,96 gpio_restart);97 if (ret) {98 dev_err(&pdev->dev, "%s: cannot register restart handler, %d\n",99 __func__, ret);100 return -ENODEV;101 }102 103 return 0;104}105 106static const struct of_device_id of_gpio_restart_match[] = {107 { .compatible = "gpio-restart", },108 {},109};110 111static struct platform_driver gpio_restart_driver = {112 .probe = gpio_restart_probe,113 .driver = {114 .name = "restart-gpio",115 .of_match_table = of_gpio_restart_match,116 },117};118 119module_platform_driver(gpio_restart_driver);120 121MODULE_AUTHOR("David Riley <davidriley@chromium.org>");122MODULE_DESCRIPTION("GPIO restart driver");123