Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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