2019-05-28 19:57:24 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2013-01-29 12:57:19 +04:00
/*
* Copyright ( C ) ST - Ericsson SA 2011 - 2013
*
* Author : Mathieu Poirier < mathieu . poirier @ linaro . org > for ST - Ericsson
* Author : Jonas Aaberg < jonas . aberg @ stericsson . com > for ST - Ericsson
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/moduleparam.h>
# include <linux/err.h>
# include <linux/uaccess.h>
# include <linux/watchdog.h>
# include <linux/platform_device.h>
# include <linux/mfd/dbx500-prcmu.h>
# define WATCHDOG_TIMEOUT 600 /* 10 minutes */
# define WATCHDOG_MIN 0
# define WATCHDOG_MAX28 268435 /* 28 bit resolution in ms == 268435.455 s */
static unsigned int timeout = WATCHDOG_TIMEOUT ;
module_param ( timeout , uint , 0 ) ;
MODULE_PARM_DESC ( timeout ,
" Watchdog timeout in seconds. default= "
__MODULE_STRING ( WATCHDOG_TIMEOUT ) " . " ) ;
static bool nowayout = WATCHDOG_NOWAYOUT ;
module_param ( nowayout , bool , 0 ) ;
MODULE_PARM_DESC ( nowayout ,
" Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
2021-09-23 02:09:47 +03:00
static int db8500_wdt_start ( struct watchdog_device * wdd )
2013-01-29 12:57:19 +04:00
{
return prcmu_enable_a9wdog ( PRCMU_WDOG_ALL ) ;
}
2021-09-23 02:09:47 +03:00
static int db8500_wdt_stop ( struct watchdog_device * wdd )
2013-01-29 12:57:19 +04:00
{
return prcmu_disable_a9wdog ( PRCMU_WDOG_ALL ) ;
}
2021-09-23 02:09:47 +03:00
static int db8500_wdt_keepalive ( struct watchdog_device * wdd )
2013-01-29 12:57:19 +04:00
{
return prcmu_kick_a9wdog ( PRCMU_WDOG_ALL ) ;
}
2021-09-23 02:09:47 +03:00
static int db8500_wdt_set_timeout ( struct watchdog_device * wdd ,
2013-01-29 12:57:19 +04:00
unsigned int timeout )
{
2021-09-23 02:09:47 +03:00
db8500_wdt_stop ( wdd ) ;
2013-01-29 12:57:19 +04:00
prcmu_load_a9wdog ( PRCMU_WDOG_ALL , timeout * 1000 ) ;
2021-09-23 02:09:47 +03:00
db8500_wdt_start ( wdd ) ;
2013-01-29 12:57:19 +04:00
return 0 ;
}
2021-09-23 02:09:47 +03:00
static const struct watchdog_info db8500_wdt_info = {
2013-01-29 12:57:19 +04:00
. options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE ,
2021-09-23 02:09:47 +03:00
. identity = " DB8500 WDT " ,
2013-01-29 12:57:19 +04:00
. firmware_version = 1 ,
} ;
2021-09-23 02:09:47 +03:00
static const struct watchdog_ops db8500_wdt_ops = {
2013-01-29 12:57:19 +04:00
. owner = THIS_MODULE ,
2021-09-23 02:09:47 +03:00
. start = db8500_wdt_start ,
. stop = db8500_wdt_stop ,
. ping = db8500_wdt_keepalive ,
. set_timeout = db8500_wdt_set_timeout ,
2013-01-29 12:57:19 +04:00
} ;
2021-09-23 02:09:47 +03:00
static struct watchdog_device db8500_wdt = {
. info = & db8500_wdt_info ,
. ops = & db8500_wdt_ops ,
2013-01-29 12:57:19 +04:00
. min_timeout = WATCHDOG_MIN ,
2021-09-23 02:09:45 +03:00
. max_timeout = WATCHDOG_MAX28 ,
2013-01-29 12:57:19 +04:00
} ;
2021-09-23 02:09:47 +03:00
static int db8500_wdt_probe ( struct platform_device * pdev )
2013-01-29 12:57:19 +04:00
{
2019-04-10 19:27:55 +03:00
struct device * dev = & pdev - > dev ;
2013-01-29 12:57:19 +04:00
int ret ;
2021-09-23 02:09:45 +03:00
timeout = 600 ; /* Default to 10 minutes */
2021-09-23 02:09:47 +03:00
db8500_wdt . parent = dev ;
watchdog_set_nowayout ( & db8500_wdt , nowayout ) ;
2013-01-29 12:57:19 +04:00
/* disable auto off on sleep */
prcmu_config_a9wdog ( PRCMU_WDOG_CPU1 , false ) ;
/* set HW initial value */
prcmu_load_a9wdog ( PRCMU_WDOG_ALL , timeout * 1000 ) ;
2021-09-23 02:09:47 +03:00
ret = devm_watchdog_register_device ( dev , & db8500_wdt ) ;
2013-01-29 12:57:19 +04:00
if ( ret )
return ret ;
2019-04-10 19:27:55 +03:00
dev_info ( dev , " initialized \n " ) ;
2013-01-29 12:57:19 +04:00
return 0 ;
}
# ifdef CONFIG_PM
2021-09-23 02:09:47 +03:00
static int db8500_wdt_suspend ( struct platform_device * pdev ,
2013-01-29 12:57:19 +04:00
pm_message_t state )
{
2021-09-23 02:09:47 +03:00
if ( watchdog_active ( & db8500_wdt ) ) {
db8500_wdt_stop ( & db8500_wdt ) ;
2013-01-29 12:57:19 +04:00
prcmu_config_a9wdog ( PRCMU_WDOG_CPU1 , true ) ;
prcmu_load_a9wdog ( PRCMU_WDOG_ALL , timeout * 1000 ) ;
2021-09-23 02:09:47 +03:00
db8500_wdt_start ( & db8500_wdt ) ;
2013-01-29 12:57:19 +04:00
}
return 0 ;
}
2021-09-23 02:09:47 +03:00
static int db8500_wdt_resume ( struct platform_device * pdev )
2013-01-29 12:57:19 +04:00
{
2021-09-23 02:09:47 +03:00
if ( watchdog_active ( & db8500_wdt ) ) {
db8500_wdt_stop ( & db8500_wdt ) ;
2013-01-29 12:57:19 +04:00
prcmu_config_a9wdog ( PRCMU_WDOG_CPU1 , false ) ;
prcmu_load_a9wdog ( PRCMU_WDOG_ALL , timeout * 1000 ) ;
2021-09-23 02:09:47 +03:00
db8500_wdt_start ( & db8500_wdt ) ;
2013-01-29 12:57:19 +04:00
}
return 0 ;
}
# else
2021-09-23 02:09:47 +03:00
# define db8500_wdt_suspend NULL
# define db8500_wdt_resume NULL
2013-01-29 12:57:19 +04:00
# endif
2021-09-23 02:09:47 +03:00
static struct platform_driver db8500_wdt_driver = {
. probe = db8500_wdt_probe ,
. suspend = db8500_wdt_suspend ,
. resume = db8500_wdt_resume ,
2013-01-29 12:57:19 +04:00
. driver = {
2021-09-23 02:09:47 +03:00
. name = " db8500_wdt " ,
2013-01-29 12:57:19 +04:00
} ,
} ;
2021-09-23 02:09:47 +03:00
module_platform_driver ( db8500_wdt_driver ) ;
2013-01-29 12:57:19 +04:00
MODULE_AUTHOR ( " Jonas Aaberg <jonas.aberg@stericsson.com> " ) ;
2021-09-23 02:09:47 +03:00
MODULE_DESCRIPTION ( " DB8500 Watchdog Driver " ) ;
2013-01-29 12:57:19 +04:00
MODULE_LICENSE ( " GPL " ) ;
2021-09-23 02:09:47 +03:00
MODULE_ALIAS ( " platform:db8500_wdt " ) ;