2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-11-17 12:51:04 +04:00
/*
* Toggles a GPIO pin to power down a device
*
* Jamie Lentin < jm @ lentin . co . uk >
* Andrew Lunn < andrew @ lunn . ch >
*
* Copyright ( C ) 2012 Jamie Lentin
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/platform_device.h>
2014-07-07 14:34:32 +04:00
# include <linux/gpio/consumer.h>
2012-11-17 12:51:04 +04:00
# include <linux/of_platform.h>
# include <linux/module.h>
2018-02-23 02:17:14 +03:00
# define DEFAULT_TIMEOUT_MS 3000
2012-11-17 12:51:04 +04:00
/*
* Hold configuration here , cannot be more than one instance of the driver
* since pm_power_off itself is global .
*/
2014-07-07 14:34:32 +04:00
static struct gpio_desc * reset_gpio ;
2018-02-23 02:17:14 +03:00
static u32 timeout = DEFAULT_TIMEOUT_MS ;
2018-11-12 00:45:38 +03:00
static u32 active_delay = 100 ;
static u32 inactive_delay = 100 ;
2012-11-17 12:51:04 +04:00
static void gpio_poweroff_do_poweroff ( void )
{
2014-07-07 14:34:32 +04:00
BUG_ON ( ! reset_gpio ) ;
2012-11-17 12:51:04 +04:00
2013-01-06 14:10:35 +04:00
/* drive it active, also inactive->active edge */
2014-07-07 14:34:32 +04:00
gpiod_direction_output ( reset_gpio , 1 ) ;
2018-11-12 00:45:38 +03:00
mdelay ( active_delay ) ;
2013-01-06 14:10:35 +04:00
/* drive inactive, also active->inactive edge */
2018-04-24 14:10:30 +03:00
gpiod_set_value_cansleep ( reset_gpio , 0 ) ;
2018-11-12 00:45:38 +03:00
mdelay ( inactive_delay ) ;
2013-01-06 14:10:35 +04:00
/* drive it active, also inactive->active edge */
2018-04-24 14:10:30 +03:00
gpiod_set_value_cansleep ( reset_gpio , 1 ) ;
2012-11-17 12:51:04 +04:00
/* give it some time */
2018-02-23 02:17:14 +03:00
mdelay ( timeout ) ;
2012-11-17 12:51:04 +04:00
WARN_ON ( 1 ) ;
}
2012-12-22 03:04:54 +04:00
static int gpio_poweroff_probe ( struct platform_device * pdev )
2012-11-17 12:51:04 +04:00
{
bool input = false ;
2015-05-18 23:45:06 +03:00
enum gpiod_flags flags ;
2012-11-17 12:51:04 +04:00
/* If a pm_power_off function has already been added, leave it alone */
if ( pm_power_off ! = NULL ) {
2014-07-07 14:34:32 +04:00
dev_err ( & pdev - > dev ,
2020-06-03 19:21:18 +03:00
" %s: pm_power_off function already registered \n " ,
2012-11-17 12:51:04 +04:00
__func__ ) ;
return - EBUSY ;
}
2018-02-23 02:17:14 +03:00
input = device_property_read_bool ( & pdev - > dev , " input " ) ;
2015-05-18 23:45:06 +03:00
if ( input )
flags = GPIOD_IN ;
else
flags = GPIOD_OUT_LOW ;
2012-11-17 12:51:04 +04:00
2018-11-12 00:45:38 +03:00
device_property_read_u32 ( & pdev - > dev , " active-delay-ms " , & active_delay ) ;
device_property_read_u32 ( & pdev - > dev , " inactive-delay-ms " ,
& inactive_delay ) ;
2018-02-23 02:17:14 +03:00
device_property_read_u32 ( & pdev - > dev , " timeout-ms " , & timeout ) ;
2015-05-18 23:45:06 +03:00
reset_gpio = devm_gpiod_get ( & pdev - > dev , NULL , flags ) ;
if ( IS_ERR ( reset_gpio ) )
return PTR_ERR ( reset_gpio ) ;
2012-11-17 12:51:04 +04:00
pm_power_off = & gpio_poweroff_do_poweroff ;
return 0 ;
}
2012-12-22 03:04:54 +04:00
static int gpio_poweroff_remove ( struct platform_device * pdev )
2012-11-17 12:51:04 +04:00
{
if ( pm_power_off = = & gpio_poweroff_do_poweroff )
pm_power_off = NULL ;
return 0 ;
}
static const struct of_device_id of_gpio_poweroff_match [ ] = {
{ . compatible = " gpio-poweroff " , } ,
{ } ,
} ;
2021-05-08 06:14:59 +03:00
MODULE_DEVICE_TABLE ( of , of_gpio_poweroff_match ) ;
2012-11-17 12:51:04 +04:00
static struct platform_driver gpio_poweroff_driver = {
. probe = gpio_poweroff_probe ,
2012-12-22 03:04:54 +04:00
. remove = gpio_poweroff_remove ,
2012-11-17 12:51:04 +04:00
. driver = {
2013-01-06 14:10:35 +04:00
. name = " poweroff-gpio " ,
. of_match_table = of_gpio_poweroff_match ,
} ,
2012-11-17 12:51:04 +04:00
} ;
module_platform_driver ( gpio_poweroff_driver ) ;
MODULE_AUTHOR ( " Jamie Lentin <jm@lentin.co.uk> " ) ;
MODULE_DESCRIPTION ( " GPIO poweroff driver " ) ;
2013-01-06 14:10:35 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;
2012-11-17 12:51:04 +04:00
MODULE_ALIAS ( " platform:poweroff-gpio " ) ;