2009-11-29 16:58:38 +02:00
/*
* Watchdog driver for Technologic Systems TS - 72 xx based SBCs
* ( TS - 7200 , TS - 7250 and TS - 7260 ) . These boards have external
* glue logic CPLD chip , which includes programmable watchdog
* timer .
*
* Copyright ( c ) 2009 Mika Westerberg < mika . westerberg @ iki . fi >
*
* This driver is based on ep93xx_wdt and wm831x_wdt drivers .
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/platform_device.h>
2017-01-31 09:33:30 -07:00
# include <linux/module.h>
2009-11-29 16:58:38 +02:00
# include <linux/watchdog.h>
2017-01-31 09:33:30 -07:00
# include <linux/io.h>
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
# define TS72XX_WDT_DEFAULT_TIMEOUT 30
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
static int timeout ;
2009-11-29 16:58:38 +02:00
module_param ( timeout , int , 0 ) ;
2017-01-31 09:33:30 -07:00
MODULE_PARM_DESC ( timeout , " Watchdog timeout in seconds. " ) ;
2009-11-29 16:58:38 +02:00
2012-03-05 16:51:11 +01:00
static bool nowayout = WATCHDOG_NOWAYOUT ;
module_param ( nowayout , bool , 0 ) ;
2009-11-29 16:58:38 +02:00
MODULE_PARM_DESC ( nowayout , " Disable watchdog shutdown on close " ) ;
2017-01-31 09:33:30 -07:00
/* priv->control_reg */
# define TS72XX_WDT_CTRL_DISABLE 0x00
# define TS72XX_WDT_CTRL_250MS 0x01
# define TS72XX_WDT_CTRL_500MS 0x02
# define TS72XX_WDT_CTRL_1SEC 0x03
# define TS72XX_WDT_CTRL_RESERVED 0x04
# define TS72XX_WDT_CTRL_2SEC 0x05
# define TS72XX_WDT_CTRL_4SEC 0x06
# define TS72XX_WDT_CTRL_8SEC 0x07
/* priv->feed_reg */
# define TS72XX_WDT_FEED_VAL 0x05
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
struct ts72xx_wdt_priv {
2009-11-29 16:58:38 +02:00
void __iomem * control_reg ;
void __iomem * feed_reg ;
2017-01-31 09:33:30 -07:00
struct watchdog_device wdd ;
unsigned char regval ;
2009-11-29 16:58:38 +02:00
} ;
2017-01-31 09:33:30 -07:00
static int ts72xx_wdt_start ( struct watchdog_device * wdd )
2009-11-29 16:58:38 +02:00
{
2017-01-31 09:33:30 -07:00
struct ts72xx_wdt_priv * priv = watchdog_get_drvdata ( wdd ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
writeb ( TS72XX_WDT_FEED_VAL , priv - > feed_reg ) ;
writeb ( priv - > regval , priv - > control_reg ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
return 0 ;
2009-11-29 16:58:38 +02:00
}
2017-01-31 09:33:30 -07:00
static int ts72xx_wdt_stop ( struct watchdog_device * wdd )
2009-11-29 16:58:38 +02:00
{
2017-01-31 09:33:30 -07:00
struct ts72xx_wdt_priv * priv = watchdog_get_drvdata ( wdd ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
writeb ( TS72XX_WDT_FEED_VAL , priv - > feed_reg ) ;
writeb ( TS72XX_WDT_CTRL_DISABLE , priv - > control_reg ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
return 0 ;
2009-11-29 16:58:38 +02:00
}
2017-01-31 09:33:30 -07:00
static int ts72xx_wdt_ping ( struct watchdog_device * wdd )
2009-11-29 16:58:38 +02:00
{
2017-01-31 09:33:30 -07:00
struct ts72xx_wdt_priv * priv = watchdog_get_drvdata ( wdd ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
writeb ( TS72XX_WDT_FEED_VAL , priv - > feed_reg ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
return 0 ;
2009-11-29 16:58:38 +02:00
}
2017-01-31 09:33:30 -07:00
static int ts72xx_wdt_settimeout ( struct watchdog_device * wdd , unsigned int to )
2009-11-29 16:58:38 +02:00
{
2017-01-31 09:33:30 -07:00
struct ts72xx_wdt_priv * priv = watchdog_get_drvdata ( wdd ) ;
if ( to = = 1 ) {
priv - > regval = TS72XX_WDT_CTRL_1SEC ;
} else if ( to = = 2 ) {
priv - > regval = TS72XX_WDT_CTRL_2SEC ;
} else if ( to < = 4 ) {
priv - > regval = TS72XX_WDT_CTRL_4SEC ;
to = 4 ;
2009-11-29 16:58:38 +02:00
} else {
2017-01-31 09:33:30 -07:00
priv - > regval = TS72XX_WDT_CTRL_8SEC ;
if ( to < = 8 )
to = 8 ;
2009-11-29 16:58:38 +02:00
}
2017-01-31 09:33:30 -07:00
wdd - > timeout = to ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
if ( watchdog_active ( wdd ) ) {
ts72xx_wdt_stop ( wdd ) ;
ts72xx_wdt_start ( wdd ) ;
2009-11-29 16:58:38 +02:00
}
2017-01-31 09:33:30 -07:00
return 0 ;
2009-11-29 16:58:38 +02:00
}
2017-01-31 09:33:30 -07:00
static const struct watchdog_info ts72xx_wdt_ident = {
. options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
2009-11-29 16:58:38 +02:00
WDIOF_MAGICCLOSE ,
. firmware_version = 1 ,
. identity = " TS-72XX WDT " ,
} ;
2017-01-31 09:33:30 -07:00
static struct watchdog_ops ts72xx_wdt_ops = {
2009-11-29 16:58:38 +02:00
. owner = THIS_MODULE ,
2017-01-31 09:33:30 -07:00
. start = ts72xx_wdt_start ,
. stop = ts72xx_wdt_stop ,
. ping = ts72xx_wdt_ping ,
. set_timeout = ts72xx_wdt_settimeout ,
2009-11-29 16:58:38 +02:00
} ;
2012-11-19 13:21:41 -05:00
static int ts72xx_wdt_probe ( struct platform_device * pdev )
2009-11-29 16:58:38 +02:00
{
2017-01-31 09:33:30 -07:00
struct ts72xx_wdt_priv * priv ;
struct watchdog_device * wdd ;
struct resource * res ;
int ret ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
priv = devm_kzalloc ( & pdev - > dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
2009-11-29 16:58:38 +02:00
return - ENOMEM ;
2017-01-31 09:33:30 -07:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
priv - > control_reg = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( priv - > control_reg ) )
return PTR_ERR ( priv - > control_reg ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
priv - > feed_reg = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( priv - > feed_reg ) )
return PTR_ERR ( priv - > feed_reg ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
wdd = & priv - > wdd ;
wdd - > info = & ts72xx_wdt_ident ;
wdd - > ops = & ts72xx_wdt_ops ;
wdd - > min_timeout = 1 ;
wdd - > max_hw_heartbeat_ms = 8000 ;
wdd - > parent = & pdev - > dev ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
watchdog_set_nowayout ( wdd , nowayout ) ;
2010-08-29 13:53:14 +03:00
2017-01-31 09:33:30 -07:00
wdd - > timeout = TS72XX_WDT_DEFAULT_TIMEOUT ;
watchdog_init_timeout ( wdd , timeout , & pdev - > dev ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
watchdog_set_drvdata ( wdd , priv ) ;
2009-11-29 16:58:38 +02:00
2017-01-31 09:33:30 -07:00
ret = devm_watchdog_register_device ( & pdev - > dev , wdd ) ;
if ( ret )
return ret ;
dev_info ( & pdev - > dev , " TS-72xx Watchdog driver \n " ) ;
2009-11-29 16:58:38 +02:00
2015-07-30 15:59:57 -07:00
return 0 ;
2009-11-29 16:58:38 +02:00
}
static struct platform_driver ts72xx_wdt_driver = {
. probe = ts72xx_wdt_probe ,
. driver = {
. name = " ts72xx-wdt " ,
} ,
} ;
2011-11-29 13:56:27 +08:00
module_platform_driver ( ts72xx_wdt_driver ) ;
2009-11-29 16:58:38 +02:00
MODULE_AUTHOR ( " Mika Westerberg <mika.westerberg@iki.fi> " ) ;
MODULE_DESCRIPTION ( " TS-72xx SBC Watchdog " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:ts72xx-wdt " ) ;