2008-11-06 13:56:21 +03:00
/*
* Watchdog driver for the wm8350
*
* Copyright ( C ) 2007 , 2008 Wolfson Microelectronics < linux @ wolfsonmicro . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation
*/
2012-02-16 03:06:19 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-11-06 13:56:21 +03:00
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/watchdog.h>
# include <linux/uaccess.h>
# include <linux/mfd/wm8350/core.h>
2012-03-05 19:51:11 +04:00
static bool nowayout = WATCHDOG_NOWAYOUT ;
module_param ( nowayout , bool , 0 ) ;
2008-11-06 13:56:21 +03:00
MODULE_PARM_DESC ( nowayout ,
" Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
static DEFINE_MUTEX ( wdt_mutex ) ;
static struct {
2012-01-23 11:26:59 +04:00
unsigned int time ; /* Seconds */
u16 val ; /* To be set in WM8350_SYSTEM_CONTROL_2 */
2008-11-06 13:56:21 +03:00
} wm8350_wdt_cfgs [ ] = {
{ 1 , 0x02 } ,
{ 2 , 0x04 } ,
{ 4 , 0x05 } ,
} ;
2012-01-23 11:26:59 +04:00
static int wm8350_wdt_set_timeout ( struct watchdog_device * wdt_dev ,
unsigned int timeout )
2008-11-06 13:56:21 +03:00
{
2012-01-23 11:26:59 +04:00
struct wm8350 * wm8350 = watchdog_get_drvdata ( wdt_dev ) ;
int ret , i ;
2008-11-06 13:56:21 +03:00
u16 reg ;
2012-01-23 11:26:59 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( wm8350_wdt_cfgs ) ; i + + )
if ( wm8350_wdt_cfgs [ i ] . time = = timeout )
break ;
if ( i = = ARRAY_SIZE ( wm8350_wdt_cfgs ) )
return - EINVAL ;
2008-11-06 13:56:21 +03:00
mutex_lock ( & wdt_mutex ) ;
wm8350_reg_unlock ( wm8350 ) ;
reg = wm8350_reg_read ( wm8350 , WM8350_SYSTEM_CONTROL_2 ) ;
reg & = ~ WM8350_WDOG_TO_MASK ;
2012-01-23 11:26:59 +04:00
reg | = wm8350_wdt_cfgs [ i ] . val ;
2008-11-06 13:56:21 +03:00
ret = wm8350_reg_write ( wm8350 , WM8350_SYSTEM_CONTROL_2 , reg ) ;
wm8350_reg_lock ( wm8350 ) ;
mutex_unlock ( & wdt_mutex ) ;
2012-02-29 23:20:58 +04:00
wdt_dev - > timeout = timeout ;
2008-11-06 13:56:21 +03:00
return ret ;
}
2012-01-23 11:26:59 +04:00
static int wm8350_wdt_start ( struct watchdog_device * wdt_dev )
2008-11-06 13:56:21 +03:00
{
2012-01-23 11:26:59 +04:00
struct wm8350 * wm8350 = watchdog_get_drvdata ( wdt_dev ) ;
2008-11-06 13:56:21 +03:00
int ret ;
u16 reg ;
mutex_lock ( & wdt_mutex ) ;
wm8350_reg_unlock ( wm8350 ) ;
reg = wm8350_reg_read ( wm8350 , WM8350_SYSTEM_CONTROL_2 ) ;
reg & = ~ WM8350_WDOG_MODE_MASK ;
reg | = 0x20 ;
ret = wm8350_reg_write ( wm8350 , WM8350_SYSTEM_CONTROL_2 , reg ) ;
wm8350_reg_lock ( wm8350 ) ;
mutex_unlock ( & wdt_mutex ) ;
return ret ;
}
2012-01-23 11:26:59 +04:00
static int wm8350_wdt_stop ( struct watchdog_device * wdt_dev )
2008-11-06 13:56:21 +03:00
{
2012-01-23 11:26:59 +04:00
struct wm8350 * wm8350 = watchdog_get_drvdata ( wdt_dev ) ;
2008-11-06 13:56:21 +03:00
int ret ;
u16 reg ;
mutex_lock ( & wdt_mutex ) ;
wm8350_reg_unlock ( wm8350 ) ;
reg = wm8350_reg_read ( wm8350 , WM8350_SYSTEM_CONTROL_2 ) ;
reg & = ~ WM8350_WDOG_MODE_MASK ;
ret = wm8350_reg_write ( wm8350 , WM8350_SYSTEM_CONTROL_2 , reg ) ;
wm8350_reg_lock ( wm8350 ) ;
mutex_unlock ( & wdt_mutex ) ;
return ret ;
}
2012-01-23 11:26:59 +04:00
static int wm8350_wdt_ping ( struct watchdog_device * wdt_dev )
2008-11-06 13:56:21 +03:00
{
2012-01-23 11:26:59 +04:00
struct wm8350 * wm8350 = watchdog_get_drvdata ( wdt_dev ) ;
2008-11-06 13:56:21 +03:00
int ret ;
u16 reg ;
mutex_lock ( & wdt_mutex ) ;
reg = wm8350_reg_read ( wm8350 , WM8350_SYSTEM_CONTROL_2 ) ;
ret = wm8350_reg_write ( wm8350 , WM8350_SYSTEM_CONTROL_2 , reg ) ;
mutex_unlock ( & wdt_mutex ) ;
return ret ;
}
2012-01-23 11:26:59 +04:00
static const struct watchdog_info wm8350_wdt_info = {
2008-11-06 13:56:21 +03:00
. options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE ,
. identity = " WM8350 Watchdog " ,
} ;
2012-01-23 11:26:59 +04:00
static const struct watchdog_ops wm8350_wdt_ops = {
2008-11-06 13:56:21 +03:00
. owner = THIS_MODULE ,
2012-01-23 11:26:59 +04:00
. start = wm8350_wdt_start ,
. stop = wm8350_wdt_stop ,
. ping = wm8350_wdt_ping ,
. set_timeout = wm8350_wdt_set_timeout ,
2008-11-06 13:56:21 +03:00
} ;
2012-01-23 11:26:59 +04:00
static struct watchdog_device wm8350_wdt = {
. info = & wm8350_wdt_info ,
. ops = & wm8350_wdt_ops ,
. timeout = 4 ,
. min_timeout = 1 ,
. max_timeout = 4 ,
2008-11-06 13:56:21 +03:00
} ;
2009-01-08 15:04:27 +03:00
static int __devinit wm8350_wdt_probe ( struct platform_device * pdev )
2008-11-06 13:56:21 +03:00
{
struct wm8350 * wm8350 = platform_get_drvdata ( pdev ) ;
if ( ! wm8350 ) {
2010-05-27 16:32:24 +04:00
pr_err ( " No driver data supplied \n " ) ;
2008-11-06 13:56:21 +03:00
return - ENODEV ;
}
2012-01-23 11:26:59 +04:00
watchdog_set_nowayout ( & wm8350_wdt , nowayout ) ;
watchdog_set_drvdata ( & wm8350_wdt , wm8350 ) ;
2008-11-06 13:56:21 +03:00
2012-01-23 11:26:59 +04:00
/* Default to 4s timeout */
wm8350_wdt_set_timeout ( & wm8350_wdt , 4 ) ;
2008-11-06 13:56:21 +03:00
2012-01-23 11:26:59 +04:00
return watchdog_register_device ( & wm8350_wdt ) ;
2008-11-06 13:56:21 +03:00
}
2009-01-08 15:04:27 +03:00
static int __devexit wm8350_wdt_remove ( struct platform_device * pdev )
2008-11-06 13:56:21 +03:00
{
2012-01-23 11:26:59 +04:00
watchdog_unregister_device ( & wm8350_wdt ) ;
2008-11-06 13:56:21 +03:00
return 0 ;
}
static struct platform_driver wm8350_wdt_driver = {
. probe = wm8350_wdt_probe ,
2009-01-08 15:04:27 +03:00
. remove = __devexit_p ( wm8350_wdt_remove ) ,
2008-11-06 13:56:21 +03:00
. driver = {
. name = " wm8350-wdt " ,
} ,
} ;
2011-11-23 19:22:36 +04:00
module_platform_driver ( wm8350_wdt_driver ) ;
2008-11-06 13:56:21 +03:00
MODULE_AUTHOR ( " Mark Brown " ) ;
MODULE_DESCRIPTION ( " WM8350 Watchdog " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:wm8350-wdt " ) ;