brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · 52cfeee Raw
116 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Toggles a GPIO pin to power down a device4 *5 * Jamie Lentin <jm@lentin.co.uk>6 * Andrew Lunn <andrew@lunn.ch>7 *8 * Copyright (C) 2012 Jamie Lentin9 */10#include <linux/kernel.h>11#include <linux/init.h>12#include <linux/delay.h>13#include <linux/platform_device.h>14#include <linux/property.h>15#include <linux/gpio/consumer.h>16#include <linux/mod_devicetable.h>17#include <linux/module.h>18#include <linux/reboot.h>19 20#define DEFAULT_TIMEOUT_MS 300021 22struct gpio_poweroff {23	struct gpio_desc *reset_gpio;24	u32 timeout_ms;25	u32 active_delay_ms;26	u32 inactive_delay_ms;27};28 29static int gpio_poweroff_do_poweroff(struct sys_off_data *data)30{31	struct gpio_poweroff *gpio_poweroff = data->cb_data;32 33	/* drive it active, also inactive->active edge */34	gpiod_direction_output(gpio_poweroff->reset_gpio, 1);35	mdelay(gpio_poweroff->active_delay_ms);36 37	/* drive inactive, also active->inactive edge */38	gpiod_set_value_cansleep(gpio_poweroff->reset_gpio, 0);39	mdelay(gpio_poweroff->inactive_delay_ms);40 41	/* drive it active, also inactive->active edge */42	gpiod_set_value_cansleep(gpio_poweroff->reset_gpio, 1);43 44	/* give it some time */45	mdelay(gpio_poweroff->timeout_ms);46 47	WARN_ON(1);48 49	return NOTIFY_DONE;50}51 52static int gpio_poweroff_probe(struct platform_device *pdev)53{54	struct gpio_poweroff *gpio_poweroff;55	bool input = false;56	enum gpiod_flags flags;57	int priority = SYS_OFF_PRIO_DEFAULT;58	int ret;59 60	gpio_poweroff = devm_kzalloc(&pdev->dev, sizeof(*gpio_poweroff), GFP_KERNEL);61	if (!gpio_poweroff)62		return -ENOMEM;63 64	input = device_property_read_bool(&pdev->dev, "input");65	if (input)66		flags = GPIOD_IN;67	else68		flags = GPIOD_OUT_LOW;69 70 71	gpio_poweroff->active_delay_ms = 100;72	gpio_poweroff->inactive_delay_ms = 100;73	gpio_poweroff->timeout_ms = DEFAULT_TIMEOUT_MS;74 75	device_property_read_u32(&pdev->dev, "active-delay-ms", &gpio_poweroff->active_delay_ms);76	device_property_read_u32(&pdev->dev, "inactive-delay-ms",77				 &gpio_poweroff->inactive_delay_ms);78	device_property_read_u32(&pdev->dev, "timeout-ms", &gpio_poweroff->timeout_ms);79	device_property_read_u32(&pdev->dev, "priority", &priority);80	if (priority > 255) {81		dev_err(&pdev->dev, "Invalid priority property: %u\n", priority);82		return -EINVAL;83	}84 85	gpio_poweroff->reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);86	if (IS_ERR(gpio_poweroff->reset_gpio))87		return PTR_ERR(gpio_poweroff->reset_gpio);88 89	ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF,90					    priority, gpio_poweroff_do_poweroff, gpio_poweroff);91	if (ret)92		return dev_err_probe(&pdev->dev, ret, "Cannot register poweroff handler\n");93 94	return 0;95}96 97static const struct of_device_id of_gpio_poweroff_match[] = {98	{ .compatible = "gpio-poweroff", },99	{},100};101MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match);102 103static struct platform_driver gpio_poweroff_driver = {104	.probe = gpio_poweroff_probe,105	.driver = {106		.name = "poweroff-gpio",107		.of_match_table = of_gpio_poweroff_match,108	},109};110 111module_platform_driver(gpio_poweroff_driver);112 113MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");114MODULE_DESCRIPTION("GPIO poweroff driver");115MODULE_ALIAS("platform:poweroff-gpio");116