linux/drivers/power/reset/gpio-poweroff.c
<<
>>
Prefs
   1/*
   2 * Toggles a GPIO pin to power down a device
   3 *
   4 * Jamie Lentin <jm@lentin.co.uk>
   5 * Andrew Lunn <andrew@lunn.ch>
   6 *
   7 * Copyright (C) 2012 Jamie Lentin
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 *
  13 */
  14#include <linux/kernel.h>
  15#include <linux/init.h>
  16#include <linux/delay.h>
  17#include <linux/platform_device.h>
  18#include <linux/gpio/consumer.h>
  19#include <linux/of_platform.h>
  20#include <linux/module.h>
  21
  22/*
  23 * Hold configuration here, cannot be more than one instance of the driver
  24 * since pm_power_off itself is global.
  25 */
  26static struct gpio_desc *reset_gpio;
  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(100);
  35        /* drive inactive, also active->inactive edge */
  36        gpiod_set_value(reset_gpio, 0);
  37        mdelay(100);
  38
  39        /* drive it active, also inactive->active edge */
  40        gpiod_set_value(reset_gpio, 1);
  41
  42        /* give it some time */
  43        mdelay(3000);
  44
  45        WARN_ON(1);
  46}
  47
  48static int gpio_poweroff_probe(struct platform_device *pdev)
  49{
  50        bool input = false;
  51        enum gpiod_flags flags;
  52
  53        /* If a pm_power_off function has already been added, leave it alone */
  54        if (pm_power_off != NULL) {
  55                dev_err(&pdev->dev,
  56                        "%s: pm_power_off function already registered",
  57                       __func__);
  58                return -EBUSY;
  59        }
  60
  61        input = of_property_read_bool(pdev->dev.of_node, "input");
  62        if (input)
  63                flags = GPIOD_IN;
  64        else
  65                flags = GPIOD_OUT_LOW;
  66
  67        reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
  68        if (IS_ERR(reset_gpio))
  69                return PTR_ERR(reset_gpio);
  70
  71        pm_power_off = &gpio_poweroff_do_poweroff;
  72        return 0;
  73}
  74
  75static int gpio_poweroff_remove(struct platform_device *pdev)
  76{
  77        if (pm_power_off == &gpio_poweroff_do_poweroff)
  78                pm_power_off = NULL;
  79
  80        return 0;
  81}
  82
  83static const struct of_device_id of_gpio_poweroff_match[] = {
  84        { .compatible = "gpio-poweroff", },
  85        {},
  86};
  87
  88static struct platform_driver gpio_poweroff_driver = {
  89        .probe = gpio_poweroff_probe,
  90        .remove = gpio_poweroff_remove,
  91        .driver = {
  92                .name = "poweroff-gpio",
  93                .of_match_table = of_gpio_poweroff_match,
  94        },
  95};
  96
  97module_platform_driver(gpio_poweroff_driver);
  98
  99MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");
 100MODULE_DESCRIPTION("GPIO poweroff driver");
 101MODULE_LICENSE("GPL v2");
 102MODULE_ALIAS("platform:poweroff-gpio");
 103