0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/delay.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/gpio/consumer.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/module.h>
0017
0018 #define DEFAULT_TIMEOUT_MS 3000
0019
0020
0021
0022
0023 static struct gpio_desc *reset_gpio;
0024 static u32 timeout = DEFAULT_TIMEOUT_MS;
0025 static u32 active_delay = 100;
0026 static u32 inactive_delay = 100;
0027
0028 static void gpio_poweroff_do_poweroff(void)
0029 {
0030 BUG_ON(!reset_gpio);
0031
0032
0033 gpiod_direction_output(reset_gpio, 1);
0034 mdelay(active_delay);
0035
0036
0037 gpiod_set_value_cansleep(reset_gpio, 0);
0038 mdelay(inactive_delay);
0039
0040
0041 gpiod_set_value_cansleep(reset_gpio, 1);
0042
0043
0044 mdelay(timeout);
0045
0046 WARN_ON(1);
0047 }
0048
0049 static int gpio_poweroff_probe(struct platform_device *pdev)
0050 {
0051 bool input = false;
0052 enum gpiod_flags flags;
0053
0054
0055 if (pm_power_off != NULL) {
0056 dev_err(&pdev->dev,
0057 "%s: pm_power_off function already registered\n",
0058 __func__);
0059 return -EBUSY;
0060 }
0061
0062 input = device_property_read_bool(&pdev->dev, "input");
0063 if (input)
0064 flags = GPIOD_IN;
0065 else
0066 flags = GPIOD_OUT_LOW;
0067
0068 device_property_read_u32(&pdev->dev, "active-delay-ms", &active_delay);
0069 device_property_read_u32(&pdev->dev, "inactive-delay-ms",
0070 &inactive_delay);
0071 device_property_read_u32(&pdev->dev, "timeout-ms", &timeout);
0072
0073 reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
0074 if (IS_ERR(reset_gpio))
0075 return PTR_ERR(reset_gpio);
0076
0077 pm_power_off = &gpio_poweroff_do_poweroff;
0078 return 0;
0079 }
0080
0081 static int gpio_poweroff_remove(struct platform_device *pdev)
0082 {
0083 if (pm_power_off == &gpio_poweroff_do_poweroff)
0084 pm_power_off = NULL;
0085
0086 return 0;
0087 }
0088
0089 static const struct of_device_id of_gpio_poweroff_match[] = {
0090 { .compatible = "gpio-poweroff", },
0091 {},
0092 };
0093 MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match);
0094
0095 static struct platform_driver gpio_poweroff_driver = {
0096 .probe = gpio_poweroff_probe,
0097 .remove = gpio_poweroff_remove,
0098 .driver = {
0099 .name = "poweroff-gpio",
0100 .of_match_table = of_gpio_poweroff_match,
0101 },
0102 };
0103
0104 module_platform_driver(gpio_poweroff_driver);
0105
0106 MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");
0107 MODULE_DESCRIPTION("GPIO poweroff driver");
0108 MODULE_LICENSE("GPL v2");
0109 MODULE_ALIAS("platform:poweroff-gpio");