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-poweroff.c (2716B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Toggles a GPIO pin to power down a device
      4 *
      5 * Jamie Lentin <jm@lentin.co.uk>
      6 * Andrew Lunn <andrew@lunn.ch>
      7 *
      8 * Copyright (C) 2012 Jamie Lentin
      9 */
     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
     18#define DEFAULT_TIMEOUT_MS 3000
     19/*
     20 * Hold configuration here, cannot be more than one instance of the driver
     21 * since pm_power_off itself is global.
     22 */
     23static struct gpio_desc *reset_gpio;
     24static u32 timeout = DEFAULT_TIMEOUT_MS;
     25static u32 active_delay = 100;
     26static u32 inactive_delay = 100;
     27
     28static void gpio_poweroff_do_poweroff(void)
     29{
     30	BUG_ON(!reset_gpio);
     31
     32	/* drive it active, also inactive->active edge */
     33	gpiod_direction_output(reset_gpio, 1);
     34	mdelay(active_delay);
     35
     36	/* drive inactive, also active->inactive edge */
     37	gpiod_set_value_cansleep(reset_gpio, 0);
     38	mdelay(inactive_delay);
     39
     40	/* drive it active, also inactive->active edge */
     41	gpiod_set_value_cansleep(reset_gpio, 1);
     42
     43	/* give it some time */
     44	mdelay(timeout);
     45
     46	WARN_ON(1);
     47}
     48
     49static int gpio_poweroff_probe(struct platform_device *pdev)
     50{
     51	bool input = false;
     52	enum gpiod_flags flags;
     53
     54	/* If a pm_power_off function has already been added, leave it alone */
     55	if (pm_power_off != NULL) {
     56		dev_err(&pdev->dev,
     57			"%s: pm_power_off function already registered\n",
     58		       __func__);
     59		return -EBUSY;
     60	}
     61
     62	input = device_property_read_bool(&pdev->dev, "input");
     63	if (input)
     64		flags = GPIOD_IN;
     65	else
     66		flags = GPIOD_OUT_LOW;
     67
     68	device_property_read_u32(&pdev->dev, "active-delay-ms", &active_delay);
     69	device_property_read_u32(&pdev->dev, "inactive-delay-ms",
     70				 &inactive_delay);
     71	device_property_read_u32(&pdev->dev, "timeout-ms", &timeout);
     72
     73	reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
     74	if (IS_ERR(reset_gpio))
     75		return PTR_ERR(reset_gpio);
     76
     77	pm_power_off = &gpio_poweroff_do_poweroff;
     78	return 0;
     79}
     80
     81static int gpio_poweroff_remove(struct platform_device *pdev)
     82{
     83	if (pm_power_off == &gpio_poweroff_do_poweroff)
     84		pm_power_off = NULL;
     85
     86	return 0;
     87}
     88
     89static const struct of_device_id of_gpio_poweroff_match[] = {
     90	{ .compatible = "gpio-poweroff", },
     91	{},
     92};
     93MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match);
     94
     95static struct platform_driver gpio_poweroff_driver = {
     96	.probe = gpio_poweroff_probe,
     97	.remove = gpio_poweroff_remove,
     98	.driver = {
     99		.name = "poweroff-gpio",
    100		.of_match_table = of_gpio_poweroff_match,
    101	},
    102};
    103
    104module_platform_driver(gpio_poweroff_driver);
    105
    106MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");
    107MODULE_DESCRIPTION("GPIO poweroff driver");
    108MODULE_LICENSE("GPL v2");
    109MODULE_ALIAS("platform:poweroff-gpio");