cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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");