Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
ae735d7c
Commit
ae735d7c
authored
Sep 15, 2009
by
Stephen Rothwell
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'watchdog/master'
parents
7c8a5ed7
376f3819
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1293 additions
and
73 deletions
+1293
-73
drivers/watchdog/Kconfig
drivers/watchdog/Kconfig
+38
-0
drivers/watchdog/Makefile
drivers/watchdog/Makefile
+3
-0
drivers/watchdog/ar7_wdt.c
drivers/watchdog/ar7_wdt.c
+54
-53
drivers/watchdog/booke_wdt.c
drivers/watchdog/booke_wdt.c
+53
-4
drivers/watchdog/coh901327_wdt.c
drivers/watchdog/coh901327_wdt.c
+1
-1
drivers/watchdog/davinci_wdt.c
drivers/watchdog/davinci_wdt.c
+17
-2
drivers/watchdog/iop_wdt.c
drivers/watchdog/iop_wdt.c
+1
-1
drivers/watchdog/nuc900_wdt.c
drivers/watchdog/nuc900_wdt.c
+353
-0
drivers/watchdog/rm9k_wdt.c
drivers/watchdog/rm9k_wdt.c
+1
-1
drivers/watchdog/sbc_fitpc2_wdt.c
drivers/watchdog/sbc_fitpc2_wdt.c
+267
-0
drivers/watchdog/sc1200wdt.c
drivers/watchdog/sc1200wdt.c
+1
-1
drivers/watchdog/wdt_pci.c
drivers/watchdog/wdt_pci.c
+11
-10
drivers/watchdog/wm831x_wdt.c
drivers/watchdog/wm831x_wdt.c
+441
-0
include/linux/mfd/wm831x/watchdog.h
include/linux/mfd/wm831x/watchdog.h
+52
-0
No files found.
drivers/watchdog/Kconfig
View file @
ae735d7c
...
...
@@ -55,6 +55,13 @@ config SOFT_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called softdog.
config WM831X_WATCHDOG
tristate "WM831x watchdog"
depends on MFD_WM831X
help
Support for the watchdog in the WM831x AudioPlus PMICs. When
the watchdog triggers the system will be reset.
config WM8350_WATCHDOG
tristate "WM8350 watchdog"
depends on MFD_WM8350
...
...
@@ -266,6 +273,15 @@ config STMP3XXX_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called stmp3xxx_wdt.
config NUC900_WATCHDOG
tristate "Nuvoton NUC900 watchdog"
depends on ARCH_W90X900
help
Say Y here if to include support for the watchdog timer
for the Nuvoton NUC900 series SoCs.
To compile this driver as a module, choose M here: the
module will be called nuc900_wdt.
# AVR32 Architecture
config AT32AP700X_WDT
...
...
@@ -369,6 +385,28 @@ config SC520_WDT
You can compile this driver directly into the kernel, or use
it as a module. The module will be called sc520_wdt.
config SBC_FITPC2_WATCHDOG
tristate "Compulab SBC-FITPC2 watchdog"
depends on X86
---help---
This is the driver for the built-in watchdog timer on the fit-PC2
Single-board computer made by Compulab.
It`s possible to enable watchdog timer either from BIOS (F2) or from booted Linux.
When "Watchdog Timer Value" enabled one can set 31-255 s operational range.
Entering BIOS setup temporary disables watchdog operation regardless to current state,
so system will not be restarted while user in BIOS setup.
Once watchdog was enabled the system will be restarted every
"Watchdog Timer Value" period, so to prevent it user can restart or
disable the watchdog.
To compile this driver as a module, choose M here: the
module will be called sbc_fitpc2_wdt.
Most people will say N.
config EUROTECH_WDT
tristate "Eurotech CPU-1220/1410 Watchdog Timer"
depends on X86
...
...
drivers/watchdog/Makefile
View file @
ae735d7c
...
...
@@ -44,6 +44,7 @@ obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
obj-$(CONFIG_ORION_WATCHDOG)
+=
orion_wdt.o
obj-$(CONFIG_COH901327_WATCHDOG)
+=
coh901327_wdt.o
obj-$(CONFIG_STMP3XXX_WATCHDOG)
+=
stmp3xxx_wdt.o
obj-$(CONFIG_NUC900_WATCHDOG)
+=
nuc900_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT)
+=
at32ap700x_wdt.o
...
...
@@ -64,6 +65,7 @@ obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
obj-$(CONFIG_ALIM7101_WDT)
+=
alim7101_wdt.o
obj-$(CONFIG_GEODE_WDT)
+=
geodewdt.o
obj-$(CONFIG_SC520_WDT)
+=
sc520_wdt.o
obj-$(CONFIG_SBC_FITPC2_WATCHDOG)
+=
sbc_fitpc2_wdt.o
obj-$(CONFIG_EUROTECH_WDT)
+=
eurotechwdt.o
obj-$(CONFIG_IB700_WDT)
+=
ib700wdt.o
obj-$(CONFIG_IBMASR)
+=
ibmasr.o
...
...
@@ -139,5 +141,6 @@ obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
# XTENSA Architecture
# Architecture Independant
obj-$(CONFIG_WM831X_WATCHDOG)
+=
wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG)
+=
wm8350_wdt.o
obj-$(CONFIG_SOFT_WATCHDOG)
+=
softdog.o
drivers/watchdog/ar7_wdt.c
View file @
ae735d7c
...
...
@@ -28,9 +28,8 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/io.h>
...
...
@@ -76,24 +75,10 @@ static unsigned expect_close;
/* XXX currently fixed, allows max margin ~68.72 secs */
#define prescale_value 0xffff
/*
Offset
of the WDT registers */
static
unsigned
long
ar7_regs_wdt
;
/*
Resource
of the WDT registers */
static
struct
resource
*
ar7_regs_wdt
;
/* Pointer to the remapped WDT IO space */
static
struct
ar7_wdt
*
ar7_wdt
;
static
void
ar7_wdt_get_regs
(
void
)
{
u16
chip_id
=
ar7_chip_id
();
switch
(
chip_id
)
{
case
AR7_CHIP_7100
:
case
AR7_CHIP_7200
:
ar7_regs_wdt
=
AR7_REGS_WDT
;
break
;
default:
ar7_regs_wdt
=
UR8_REGS_WDT
;
break
;
}
}
static
void
ar7_wdt_kick
(
u32
value
)
{
...
...
@@ -202,20 +187,6 @@ static int ar7_wdt_release(struct inode *inode, struct file *file)
return
0
;
}
static
int
ar7_wdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_HALT
||
code
==
SYS_POWER_OFF
)
if
(
!
nowayout
)
ar7_wdt_disable_wdt
();
return
NOTIFY_DONE
;
}
static
struct
notifier_block
ar7_wdt_notifier
=
{
.
notifier_call
=
ar7_wdt_notify_sys
,
};
static
ssize_t
ar7_wdt_write
(
struct
file
*
file
,
const
char
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
...
...
@@ -299,56 +270,86 @@ static struct miscdevice ar7_wdt_miscdev = {
.
fops
=
&
ar7_wdt_fops
,
};
static
int
__
init
ar7_wdt_init
(
void
)
static
int
__
devinit
ar7_wdt_probe
(
struct
platform_device
*
pdev
)
{
int
rc
;
spin_lock_init
(
&
wdt_lock
);
ar7_wdt_get_regs
();
ar7_regs_wdt
=
platform_get_resource_byname
(
pdev
,
IORESOURCE_MEM
,
"regs"
);
if
(
!
ar7_regs_wdt
)
{
printk
(
KERN_ERR
DRVNAME
": could not get registers resource
\n
"
);
rc
=
-
ENODEV
;
goto
out
;
}
if
(
!
request_mem_region
(
ar7_regs_wdt
,
sizeof
(
struct
ar7_wdt
)
,
LONGNAME
))
{
if
(
!
request_mem_region
(
ar7_regs_wdt
->
start
,
resource_size
(
ar7_regs_wdt
),
LONGNAME
))
{
printk
(
KERN_WARNING
DRVNAME
": watchdog I/O region busy
\n
"
);
return
-
EBUSY
;
rc
=
-
EBUSY
;
goto
out
;
}
ar7_wdt
=
(
struct
ar7_wdt
*
)
ioremap
(
ar7_regs_wdt
,
sizeof
(
struct
ar7_wdt
));
ar7_wdt
=
ioremap
(
ar7_regs_wdt
->
start
,
resource_size
(
ar7_regs_wdt
));
if
(
!
ar7_wdt
)
{
printk
(
KERN_ERR
DRVNAME
": could not ioremap registers
\n
"
);
rc
=
-
ENXIO
;
goto
out_mem_region
;
}
ar7_wdt_disable_wdt
();
ar7_wdt_prescale
(
prescale_value
);
ar7_wdt_update_margin
(
margin
);
rc
=
register_reboot_notifier
(
&
ar7_wdt_notifier
);
if
(
rc
)
{
printk
(
KERN_ERR
DRVNAME
": unable to register reboot notifier
\n
"
);
goto
out_alloc
;
}
rc
=
misc_register
(
&
ar7_wdt_miscdev
);
if
(
rc
)
{
printk
(
KERN_ERR
DRVNAME
": unable to register misc device
\n
"
);
goto
out_
register
;
goto
out_
alloc
;
}
goto
out
;
out_register:
unregister_reboot_notifier
(
&
ar7_wdt_notifier
);
out_alloc:
iounmap
(
ar7_wdt
);
release_mem_region
(
ar7_regs_wdt
,
sizeof
(
struct
ar7_wdt
));
out_mem_region:
release_mem_region
(
ar7_regs_wdt
->
start
,
resource_size
(
ar7_regs_wdt
));
out:
return
rc
;
}
static
void
__exit
ar7_wdt_cleanup
(
void
)
static
int
__devexit
ar7_wdt_remove
(
struct
platform_device
*
pdev
)
{
misc_deregister
(
&
ar7_wdt_miscdev
);
unregister_reboot_notifier
(
&
ar7_wdt_notifier
);
iounmap
(
ar7_wdt
);
release_mem_region
(
ar7_regs_wdt
,
sizeof
(
struct
ar7_wdt
));
release_mem_region
(
ar7_regs_wdt
->
start
,
resource_size
(
ar7_regs_wdt
));
return
0
;
}
static
void
ar7_wdt_shutdown
(
struct
platform_device
*
pdev
)
{
if
(
!
nowayout
)
ar7_wdt_disable_wdt
();
}
static
struct
platform_driver
ar7_wdt_driver
=
{
.
probe
=
ar7_wdt_probe
,
.
remove
=
__devexit_p
(
ar7_wdt_remove
),
.
shutdown
=
ar7_wdt_shutdown
,
.
driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"ar7_wdt"
,
},
};
static
int
__init
ar7_wdt_init
(
void
)
{
return
platform_driver_register
(
&
ar7_wdt_driver
);
}
static
void
__exit
ar7_wdt_cleanup
(
void
)
{
platform_driver_unregister
(
&
ar7_wdt_driver
);
}
module_init
(
ar7_wdt_init
);
...
...
drivers/watchdog/booke_wdt.c
View file @
ae735d7c
...
...
@@ -22,6 +22,8 @@
#include <asm/reg_booke.h>
#include <asm/system.h>
#include <asm/time.h>
#include <asm/div64.h>
/* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
* Also, the wdt_period sets the watchdog timer period timeout.
...
...
@@ -32,7 +34,7 @@
*/
#ifdef CONFIG_FSL_BOOKE
#define WDT_PERIOD_DEFAULT
63
/* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */
#define WDT_PERIOD_DEFAULT
38
/* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */
#else
#define WDT_PERIOD_DEFAULT 3
/* Refer to the PPC40x and PPC4xx manuals */
#endif
/* for timing information */
...
...
@@ -41,7 +43,7 @@ u32 booke_wdt_enabled;
u32
booke_wdt_period
=
WDT_PERIOD_DEFAULT
;
#ifdef CONFIG_FSL_BOOKE
#define WDTP(x) ((((
63-x)&0x3)<<30)|(((63-
x)&0x3c)<<15))
#define WDTP(x) ((((
x)&0x3)<<30)|(((
x)&0x3c)<<15))
#define WDTP_MASK (WDTP(0))
#else
#define WDTP(x) (TCR_WP(x))
...
...
@@ -50,6 +52,45 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
static
DEFINE_SPINLOCK
(
booke_wdt_lock
);
/* For the specified period, determine the number of seconds
* corresponding to the reset time. There will be a watchdog
* exception at approximately 3/5 of this time.
*
* The formula to calculate this is given by:
* 2.5 * (2^(63-period+1)) / timebase_freq
*
* In order to simplify things, we assume that period is
* at least 1. This will still result in a very long timeout.
*/
static
unsigned
long
long
period_to_sec
(
unsigned
int
period
)
{
unsigned
long
long
tmp
=
1ULL
<<
(
64
-
period
);
unsigned
long
tmp2
=
ppc_tb_freq
;
/* tmp may be a very large number and we don't want to overflow,
* so divide the timebase freq instead of multiplying tmp
*/
tmp2
=
tmp2
/
5
*
2
;
do_div
(
tmp
,
tmp2
);
return
tmp
;
}
/*
* This procedure will find the highest period which will give a timeout
* greater than the one required. e.g. for a bus speed of 66666666 and
* and a parameter of 2 secs, then this procedure will return a value of 38.
*/
static
unsigned
int
sec_to_period
(
unsigned
int
secs
)
{
unsigned
int
period
;
for
(
period
=
63
;
period
>
0
;
period
--
)
{
if
(
period_to_sec
(
period
)
>=
secs
)
return
period
;
}
return
0
;
}
static
void
__booke_wdt_ping
(
void
*
data
)
{
mtspr
(
SPRN_TSR
,
TSR_ENW
|
TSR_WIS
);
...
...
@@ -93,7 +134,7 @@ static long booke_wdt_ioctl(struct file *file,
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
(
arg
,
&
ident
,
sizeof
(
struct
watchdog_info
)))
if
(
copy_to_user
(
(
void
*
)
arg
,
&
ident
,
sizeof
(
ident
)))
return
-
EFAULT
;
case
WDIOC_GETSTATUS
:
return
put_user
(
ident
.
options
,
p
);
...
...
@@ -115,8 +156,16 @@ static long booke_wdt_ioctl(struct file *file,
booke_wdt_ping
();
return
0
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
booke_wdt_period
,
p
))
if
(
get_user
(
tmp
,
p
))
return
-
EFAULT
;
#ifdef CONFIG_FSL_BOOKE
/* period of 1 gives the largest possible timeout */
if
(
tmp
>
period_to_sec
(
1
))
return
-
EINVAL
;
booke_wdt_period
=
sec_to_period
(
tmp
);
#else
booke_wdt_period
=
tmp
;
#endif
mtspr
(
SPRN_TCR
,
(
mfspr
(
SPRN_TCR
)
&
~
WDTP_MASK
)
|
WDTP
(
booke_wdt_period
));
return
0
;
...
...
drivers/watchdog/coh901327_wdt.c
View file @
ae735d7c
...
...
@@ -110,7 +110,7 @@ static void coh901327_enable(u16 timeout)
* Wait 3 32 kHz cycles for it to take effect
*/
freq
=
clk_get_rate
(
clk
);
delay_ns
=
(
1000000000
+
freq
-
1
)
/
freq
;
/* Freq to ns and round up */
delay_ns
=
DIV_ROUND_UP
(
1000000000
,
freq
)
;
/* Freq to ns and round up */
delay_ns
=
3
*
delay_ns
;
/* Wait 3 cycles */
ndelay
(
delay_ns
);
/* Enable the watchdog interrupt */
...
...
drivers/watchdog/davinci_wdt.c
View file @
ae735d7c
...
...
@@ -25,6 +25,7 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/clk.h>
#define MODULE_NAME "DAVINCI-WDT: "
...
...
@@ -69,6 +70,7 @@ static unsigned long wdt_status;
static
struct
resource
*
wdt_mem
;
static
void
__iomem
*
wdt_base
;
struct
clk
*
wdt_clk
;
static
void
wdt_service
(
void
)
{
...
...
@@ -86,6 +88,9 @@ static void wdt_enable(void)
{
u32
tgcr
;
u32
timer_margin
;
unsigned
long
wdt_freq
;
wdt_freq
=
clk_get_rate
(
wdt_clk
);
spin_lock
(
&
io_lock
);
...
...
@@ -99,9 +104,9 @@ static void wdt_enable(void)
iowrite32
(
0
,
wdt_base
+
TIM12
);
iowrite32
(
0
,
wdt_base
+
TIM34
);
/* set timeout period */
timer_margin
=
(((
u64
)
heartbeat
*
CLOCK_TICK_RATE
)
&
0xffffffff
);
timer_margin
=
(((
u64
)
heartbeat
*
wdt_freq
)
&
0xffffffff
);
iowrite32
(
timer_margin
,
wdt_base
+
PRD12
);
timer_margin
=
(((
u64
)
heartbeat
*
CLOCK_TICK_RATE
)
>>
32
);
timer_margin
=
(((
u64
)
heartbeat
*
wdt_freq
)
>>
32
);
iowrite32
(
timer_margin
,
wdt_base
+
PRD34
);
/* enable run continuously */
iowrite32
(
ENAMODE12_PERIODIC
,
wdt_base
+
TCR
);
...
...
@@ -199,6 +204,12 @@ static int __devinit davinci_wdt_probe(struct platform_device *pdev)
struct
resource
*
res
;
struct
device
*
dev
=
&
pdev
->
dev
;
wdt_clk
=
clk_get
(
dev
,
NULL
);
if
(
WARN_ON
(
IS_ERR
(
wdt_clk
)))
return
PTR_ERR
(
wdt_clk
);
clk_enable
(
wdt_clk
);
if
(
heartbeat
<
1
||
heartbeat
>
MAX_HEARTBEAT
)
heartbeat
=
DEFAULT_HEARTBEAT
;
...
...
@@ -245,6 +256,10 @@ static int __devexit davinci_wdt_remove(struct platform_device *pdev)
kfree
(
wdt_mem
);
wdt_mem
=
NULL
;
}
clk_disable
(
wdt_clk
);
clk_put
(
wdt_clk
);
return
0
;
}
...
...
drivers/watchdog/iop_wdt.c
View file @
ae735d7c
...
...
@@ -139,7 +139,7 @@ static long iop_wdt_ioctl(struct file *file,
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
(
argp
,
&
ident
,
sizeof
ident
))
if
(
copy_to_user
(
argp
,
&
ident
,
sizeof
(
ident
)
))
ret
=
-
EFAULT
;
else
ret
=
0
;
...
...
drivers/watchdog/nuc900_wdt.c
0 → 100644
View file @
ae735d7c
/*
* Copyright (c) 2009 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.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;version 2 of the License.
*
*/
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/uaccess.h>
#define REG_WTCR 0x1c
#define WTCLK (0x01 << 10)
#define WTE (0x01 << 7)
/*wdt enable*/
#define WTIS (0x03 << 4)
#define WTIF (0x01 << 3)
#define WTRF (0x01 << 2)
#define WTRE (0x01 << 1)
#define WTR (0x01 << 0)
/*
* The watchdog time interval can be calculated via following formula:
* WTIS real time interval (formula)
* 0x00 ((2^ 14 ) * ((external crystal freq) / 256))seconds
* 0x01 ((2^ 16 ) * ((external crystal freq) / 256))seconds
* 0x02 ((2^ 18 ) * ((external crystal freq) / 256))seconds
* 0x03 ((2^ 20 ) * ((external crystal freq) / 256))seconds
*
* The external crystal freq is 15Mhz in the nuc900 evaluation board.
* So 0x00 = +-0.28 seconds, 0x01 = +-1.12 seconds, 0x02 = +-4.48 seconds,
* 0x03 = +- 16.92 seconds..
*/
#define WDT_HW_TIMEOUT 0x02
#define WDT_TIMEOUT (HZ/2)
#define WDT_HEARTBEAT 15
static
int
heartbeat
=
WDT_HEARTBEAT
;
module_param
(
heartbeat
,
int
,
0
);
MODULE_PARM_DESC
(
heartbeat
,
"Watchdog heartbeats in seconds. "
"(default = "
__MODULE_STRING
(
WDT_HEARTBEAT
)
")"
);
static
int
nowayout
=
WATCHDOG_NOWAYOUT
;
module_param
(
nowayout
,
int
,
0
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started "
"(default="
__MODULE_STRING
(
WATCHDOG_NOWAYOUT
)
")"
);
struct
nuc900_wdt
{
struct
resource
*
res
;
struct
clk
*
wdt_clock
;
struct
platform_device
*
pdev
;
void
__iomem
*
wdt_base
;
char
expect_close
;
struct
timer_list
timer
;
spinlock_t
wdt_lock
;
unsigned
long
next_heartbeat
;
};
static
unsigned
long
nuc900wdt_busy
;
struct
nuc900_wdt
*
nuc900_wdt
;
static
inline
void
nuc900_wdt_keepalive
(
void
)
{
unsigned
int
val
;
spin_lock
(
&
nuc900_wdt
->
wdt_lock
);
val
=
__raw_readl
(
nuc900_wdt
->
wdt_base
+
REG_WTCR
);
val
|=
(
WTR
|
WTIF
);
__raw_writel
(
val
,
nuc900_wdt
->
wdt_base
+
REG_WTCR
);
spin_unlock
(
&
nuc900_wdt
->
wdt_lock
);
}
static
inline
void
nuc900_wdt_start
(
void
)
{
unsigned
int
val
;
spin_lock
(
&
nuc900_wdt
->
wdt_lock
);
val
=
__raw_readl
(
nuc900_wdt
->
wdt_base
+
REG_WTCR
);
val
|=
(
WTRE
|
WTE
|
WTR
|
WTCLK
|
WTIF
);
val
&=
~
WTIS
;
val
|=
(
WDT_HW_TIMEOUT
<<
0x04
);
__raw_writel
(
val
,
nuc900_wdt
->
wdt_base
+
REG_WTCR
);
spin_unlock
(
&
nuc900_wdt
->
wdt_lock
);
nuc900_wdt
->
next_heartbeat
=
jiffies
+
heartbeat
*
HZ
;
mod_timer
(
&
nuc900_wdt
->
timer
,
jiffies
+
WDT_TIMEOUT
);
}
static
inline
void
nuc900_wdt_stop
(
void
)
{
unsigned
int
val
;
del_timer
(
&
nuc900_wdt
->
timer
);
spin_lock
(
&
nuc900_wdt
->
wdt_lock
);
val
=
__raw_readl
(
nuc900_wdt
->
wdt_base
+
REG_WTCR
);
val
&=
~
WTE
;
__raw_writel
(
val
,
nuc900_wdt
->
wdt_base
+
REG_WTCR
);
spin_unlock
(
&
nuc900_wdt
->
wdt_lock
);
}
static
inline
void
nuc900_wdt_ping
(
void
)
{
nuc900_wdt
->
next_heartbeat
=
jiffies
+
heartbeat
*
HZ
;
}
static
int
nuc900_wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
test_and_set_bit
(
0
,
&
nuc900wdt_busy
))
return
-
EBUSY
;
nuc900_wdt_start
();
return
nonseekable_open
(
inode
,
file
);
}
static
int
nuc900_wdt_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
nuc900_wdt
->
expect_close
==
42
)
nuc900_wdt_stop
();
else
{
dev_crit
(
&
nuc900_wdt
->
pdev
->
dev
,
"Unexpected close, not stopping watchdog!
\n
"
);
nuc900_wdt_ping
();
}
nuc900_wdt
->
expect_close
=
0
;
clear_bit
(
0
,
&
nuc900wdt_busy
);
return
0
;
}
static
const
struct
watchdog_info
nuc900_wdt_info
=
{
.
identity
=
"nuc900 watchdog"
,
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
};
static
long
nuc900_wdt_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
__user
*
p
=
argp
;
int
new_value
;
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
return
copy_to_user
(
argp
,
&
nuc900_wdt_info
,
sizeof
(
nuc900_wdt_info
))
?
-
EFAULT
:
0
;
case
WDIOC_GETSTATUS
:
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
0
,
p
);
case
WDIOC_KEEPALIVE
:
nuc900_wdt_ping
();
return
0
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
new_value
,
p
))
return
-
EFAULT
;
heartbeat
=
new_value
;
nuc900_wdt_ping
();
return
put_user
(
new_value
,
p
);
case
WDIOC_GETTIMEOUT
:
return
put_user
(
heartbeat
,
p
);
default:
return
-
ENOTTY
;
}
}
static
ssize_t
nuc900_wdt_write
(
struct
file
*
file
,
const
char
__user
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
if
(
!
len
)
return
0
;
/* Scan for magic character */
if
(
!
nowayout
)
{
size_t
i
;
nuc900_wdt
->
expect_close
=
0
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
{
nuc900_wdt
->
expect_close
=
42
;
break
;
}
}
}
nuc900_wdt_ping
();
return
len
;
}
static
void
nuc900_wdt_timer_ping
(
unsigned
long
data
)
{
if
(
time_before
(
jiffies
,
nuc900_wdt
->
next_heartbeat
))
{
nuc900_wdt_keepalive
();
mod_timer
(
&
nuc900_wdt
->
timer
,
jiffies
+
WDT_TIMEOUT
);
}
else
dev_warn
(
&
nuc900_wdt
->
pdev
->
dev
,
"Will reset the machine !
\n
"
);
}
static
const
struct
file_operations
nuc900wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
unlocked_ioctl
=
nuc900_wdt_ioctl
,
.
open
=
nuc900_wdt_open
,
.
release
=
nuc900_wdt_close
,
.
write
=
nuc900_wdt_write
,
};
static
struct
miscdevice
nuc900wdt_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
nuc900wdt_fops
,
};
static
int
__devinit
nuc900wdt_probe
(
struct
platform_device
*
pdev
)
{
int
ret
=
0
;
nuc900_wdt
=
kzalloc
(
sizeof
(
struct
nuc900_wdt
),
GFP_KERNEL
);
if
(
!
nuc900_wdt
)
return
-
ENOMEM
;
nuc900_wdt
->
pdev
=
pdev
;
spin_lock_init
(
&
nuc900_wdt
->
wdt_lock
);
nuc900_wdt
->
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
nuc900_wdt
->
res
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"no memory resource specified
\n
"
);
ret
=
-
ENOENT
;
goto
err_get
;
}
if
(
!
request_mem_region
(
nuc900_wdt
->
res
->
start
,
resource_size
(
nuc900_wdt
->
res
),
pdev
->
name
))
{
dev_err
(
&
pdev
->
dev
,
"failed to get memory region
\n
"
);
ret
=
-
ENOENT
;
goto
err_get
;
}
nuc900_wdt
->
wdt_base
=
ioremap
(
nuc900_wdt
->
res
->
start
,
resource_size
(
nuc900_wdt
->
res
));
if
(
nuc900_wdt
->
wdt_base
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"failed to ioremap() region
\n
"
);
ret
=
-
EINVAL
;
goto
err_req
;
}
nuc900_wdt
->
wdt_clock
=
clk_get
(
&
pdev
->
dev
,
NULL
);
if
(
IS_ERR
(
nuc900_wdt
->
wdt_clock
))
{
dev_err
(
&
pdev
->
dev
,
"failed to find watchdog clock source
\n
"
);
ret
=
PTR_ERR
(
nuc900_wdt
->
wdt_clock
);
goto
err_map
;
}
clk_enable
(
nuc900_wdt
->
wdt_clock
);
setup_timer
(
&
nuc900_wdt
->
timer
,
nuc900_wdt_timer_ping
,
0
);
if
(
misc_register
(
&
nuc900wdt_miscdev
))
{
dev_err
(
&
pdev
->
dev
,
"err register miscdev on minor=%d (%d)
\n
"
,
WATCHDOG_MINOR
,
ret
);
goto
err_clk
;
}
return
0
;
err_clk:
clk_disable
(
nuc900_wdt
->
wdt_clock
);
clk_put
(
nuc900_wdt
->
wdt_clock
);
err_map:
iounmap
(
nuc900_wdt
->
wdt_base
);
err_req:
release_mem_region
(
nuc900_wdt
->
res
->
start
,
resource_size
(
nuc900_wdt
->
res
));
err_get:
kfree
(
nuc900_wdt
);
return
ret
;
}
static
int
__devexit
nuc900wdt_remove
(
struct
platform_device
*
pdev
)
{
misc_deregister
(
&
nuc900wdt_miscdev
);
clk_disable
(
nuc900_wdt
->
wdt_clock
);
clk_put
(
nuc900_wdt
->
wdt_clock
);
iounmap
(
nuc900_wdt
->
wdt_base
);
release_mem_region
(
nuc900_wdt
->
res
->
start
,
resource_size
(
nuc900_wdt
->
res
));
kfree
(
nuc900_wdt
);
return
0
;
}
static
struct
platform_driver
nuc900wdt_driver
=
{
.
probe
=
nuc900wdt_probe
,
.
remove
=
__devexit_p
(
nuc900wdt_remove
),
.
driver
=
{
.
name
=
"nuc900-wdt"
,
.
owner
=
THIS_MODULE
,
},
};
static
int
__init
nuc900_wdt_init
(
void
)
{
return
platform_driver_register
(
&
nuc900wdt_driver
);
}
static
void
__exit
nuc900_wdt_exit
(
void
)
{
platform_driver_unregister
(
&
nuc900wdt_driver
);
}
module_init
(
nuc900_wdt_init
);
module_exit
(
nuc900_wdt_exit
);
MODULE_AUTHOR
(
"Wan ZongShun <mcuos.com@gmail.com>"
);
MODULE_DESCRIPTION
(
"Watchdog driver for NUC900"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
MODULE_ALIAS
(
"platform:nuc900-wdt"
);
drivers/watchdog/rm9k_wdt.c
View file @
ae735d7c
...
...
@@ -340,7 +340,7 @@ static const struct resource *wdt_gpi_get_resource(struct platform_device *pdv,
const
char
*
name
,
unsigned
int
type
)
{
char
buf
[
80
];
if
(
snprintf
(
buf
,
sizeof
buf
,
"%s_0"
,
name
)
>=
sizeof
buf
)
if
(
snprintf
(
buf
,
sizeof
(
buf
),
"%s_0"
,
name
)
>=
sizeof
(
buf
)
)
return
NULL
;
return
platform_get_resource_byname
(
pdv
,
type
,
buf
);
}
...
...
drivers/watchdog/sbc_fitpc2_wdt.c
0 → 100644
View file @
ae735d7c
/*
* Watchdog driver for SBC-FITPC2 board
*
* Author: Denis Turischev <denis@compulab.co.il>
*
* Adapted from the IXP2000 watchdog driver by Deepak Saxena.
*
* 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME " WATCHDOG: " fmt
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/dmi.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/system.h>
static
int
nowayout
=
WATCHDOG_NOWAYOUT
;
static
unsigned
int
margin
=
60
;
/* (secs) Default is 1 minute */
static
unsigned
long
wdt_status
;
static
DEFINE_SPINLOCK
(
wdt_lock
);
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
#define COMMAND_PORT 0x4c
#define DATA_PORT 0x48
#define IFACE_ON_COMMAND 1
#define REBOOT_COMMAND 2
#define WATCHDOG_NAME "SBC-FITPC2 Watchdog"
static
void
wdt_send_data
(
unsigned
char
command
,
unsigned
char
data
)
{
outb
(
command
,
COMMAND_PORT
);
mdelay
(
100
);
outb
(
data
,
DATA_PORT
);
mdelay
(
200
);
}
static
void
wdt_enable
(
void
)
{
spin_lock
(
&
wdt_lock
);
wdt_send_data
(
IFACE_ON_COMMAND
,
1
);
wdt_send_data
(
REBOOT_COMMAND
,
margin
);
spin_unlock
(
&
wdt_lock
);
}
static
void
wdt_disable
(
void
)
{
spin_lock
(
&
wdt_lock
);
wdt_send_data
(
IFACE_ON_COMMAND
,
0
);
wdt_send_data
(
REBOOT_COMMAND
,
0
);
spin_unlock
(
&
wdt_lock
);
}
static
int
fitpc2_wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
test_and_set_bit
(
WDT_IN_USE
,
&
wdt_status
))
return
-
EBUSY
;
clear_bit
(
WDT_OK_TO_CLOSE
,
&
wdt_status
);
wdt_enable
();
return
nonseekable_open
(
inode
,
file
);
}
static
ssize_t
fitpc2_wdt_write
(
struct
file
*
file
,
const
char
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
size_t
i
;
if
(
!
len
)
return
0
;
if
(
nowayout
)
{
len
=
0
;
goto
out
;
}
clear_bit
(
WDT_OK_TO_CLOSE
,
&
wdt_status
);
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
set_bit
(
WDT_OK_TO_CLOSE
,
&
wdt_status
);
}
out:
wdt_enable
();
return
len
;
}
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_MAGICCLOSE
|
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
,
.
identity
=
WATCHDOG_NAME
,
};
static
long
fitpc2_wdt_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
ret
=
-
ENOTTY
;
int
time
;
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
ret
=
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
))
?
-
EFAULT
:
0
;
break
;
case
WDIOC_GETSTATUS
:
ret
=
put_user
(
0
,
(
int
*
)
arg
);
break
;
case
WDIOC_GETBOOTSTATUS
:
ret
=
put_user
(
0
,
(
int
*
)
arg
);
break
;
case
WDIOC_KEEPALIVE
:
wdt_enable
();
ret
=
0
;
break
;
case
WDIOC_SETTIMEOUT
:
ret
=
get_user
(
time
,
(
int
*
)
arg
);
if
(
ret
)
break
;
if
(
time
<
31
||
time
>
255
)
{
ret
=
-
EINVAL
;
break
;
}
margin
=
time
;
wdt_enable
();
/* Fall through */
case
WDIOC_GETTIMEOUT
:
ret
=
put_user
(
margin
,
(
int
*
)
arg
);
break
;
}
return
ret
;
}
static
int
fitpc2_wdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
test_bit
(
WDT_OK_TO_CLOSE
,
&
wdt_status
))
{
wdt_disable
();
pr_info
(
"Device disabled
\n
"
);
}
else
{
pr_warning
(
"Device closed unexpectedly -"
" timer will not stop
\n
"
);
wdt_enable
();
}
clear_bit
(
WDT_IN_USE
,
&
wdt_status
);
clear_bit
(
WDT_OK_TO_CLOSE
,
&
wdt_status
);
return
0
;
}
static
const
struct
file_operations
fitpc2_wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
fitpc2_wdt_write
,
.
unlocked_ioctl
=
fitpc2_wdt_ioctl
,
.
open
=
fitpc2_wdt_open
,
.
release
=
fitpc2_wdt_release
,
};
static
struct
miscdevice
fitpc2_wdt_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
fitpc2_wdt_fops
,
};
static
int
__init
fitpc2_wdt_init
(
void
)
{
int
err
;
if
(
strcmp
(
"SBC-FITPC2"
,
dmi_get_system_info
(
DMI_BOARD_NAME
)))
{
pr_info
(
"board name is: %s. Should be SBC-FITPC2
\n
"
,
dmi_get_system_info
(
DMI_BOARD_NAME
));
return
-
ENODEV
;
}
if
(
!
request_region
(
COMMAND_PORT
,
1
,
WATCHDOG_NAME
))
{
pr_err
(
"I/O address 0x%04x already in use
\n
"
,
COMMAND_PORT
);
return
-
EIO
;
}
if
(
!
request_region
(
DATA_PORT
,
1
,
WATCHDOG_NAME
))
{
pr_err
(
"I/O address 0x%04x already in use
\n
"
,
DATA_PORT
);
err
=
-
EIO
;
goto
err_data_port
;
}
if
(
margin
<
31
||
margin
>
255
)
{
pr_err
(
"margin must be in range 31 - 255"
" seconds, you tried to set %d
\n
"
,
margin
);
err
=
-
EINVAL
;
goto
err_margin
;
}
err
=
misc_register
(
&
fitpc2_wdt_miscdev
);
if
(
!
err
)
{
pr_err
(
"cannot register miscdev on minor=%d (err=%d)
\n
"
,
WATCHDOG_MINOR
,
err
);
goto
err_margin
;
}
return
0
;
err_margin:
release_region
(
DATA_PORT
,
1
);
err_data_port:
release_region
(
COMMAND_PORT
,
1
);
return
err
;
}
static
void
__exit
fitpc2_wdt_exit
(
void
)
{
misc_deregister
(
&
fitpc2_wdt_miscdev
);
release_region
(
DATA_PORT
,
1
);
release_region
(
COMMAND_PORT
,
1
);
}
module_init
(
fitpc2_wdt_init
);
module_exit
(
fitpc2_wdt_exit
);
MODULE_AUTHOR
(
"Denis Turischev <denis@compulab.co.il>"
);
MODULE_DESCRIPTION
(
"SBC-FITPC2 Watchdog"
);
module_param
(
margin
,
int
,
0
);
MODULE_PARM_DESC
(
margin
,
"Watchdog margin in seconds (default 60s)"
);
module_param
(
nowayout
,
int
,
0
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
drivers/watchdog/sc1200wdt.c
View file @
ae735d7c
...
...
@@ -197,7 +197,7 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
(
argp
,
&
ident
,
sizeof
ident
))
if
(
copy_to_user
(
argp
,
&
ident
,
sizeof
(
ident
)
))
return
-
EFAULT
;
return
0
;
...
...
drivers/watchdog/wdt_pci.c
View file @
ae735d7c
...
...
@@ -80,7 +80,7 @@ static unsigned long open_lock;
static
DEFINE_SPINLOCK
(
wdtpci_lock
);
static
char
expect_close
;
static
in
t
io
;
static
resource_size_
t
io
;
static
int
irq
;
/* Default timeout */
...
...
@@ -647,14 +647,15 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
goto
out_pci
;
}
irq
=
dev
->
irq
;
io
=
pci_resource_start
(
dev
,
2
);
if
(
request_region
(
io
,
16
,
"wdt_pci"
)
==
NULL
)
{
printk
(
KERN_ERR
PFX
"I/O address 0x%04x already in use
\n
"
,
io
);
if
(
pci_request_region
(
dev
,
2
,
"wdt_pci"
))
{
printk
(
KERN_ERR
PFX
"I/O address 0x%llx already in use
\n
"
,
(
unsigned
long
long
)
pci_resource_start
(
dev
,
2
));
goto
out_pci
;
}
irq
=
dev
->
irq
;
io
=
pci_resource_start
(
dev
,
2
);
if
(
request_irq
(
irq
,
wdtpci_interrupt
,
IRQF_DISABLED
|
IRQF_SHARED
,
"wdt_pci"
,
&
wdtpci_miscdev
))
{
printk
(
KERN_ERR
PFX
"IRQ %d is not free
\n
"
,
irq
);
...
...
@@ -662,8 +663,8 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
}
printk
(
KERN_INFO
"PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%
04
x (Interrupt %d)
\n
"
,
io
,
irq
);
"PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%
ll
x (Interrupt %d)
\n
"
,
(
unsigned
long
long
)
io
,
irq
);
/* Check that the heartbeat value is within its range;
if not reset to the default */
...
...
@@ -717,7 +718,7 @@ out_rbt:
out_irq:
free_irq
(
irq
,
&
wdtpci_miscdev
);
out_reg:
release_region
(
io
,
16
);
pci_release_region
(
dev
,
2
);
out_pci:
pci_disable_device
(
dev
);
goto
out
;
...
...
@@ -733,7 +734,7 @@ static void __devexit wdtpci_remove_one(struct pci_dev *pdev)
misc_deregister
(
&
temp_miscdev
);
unregister_reboot_notifier
(
&
wdtpci_notifier
);
free_irq
(
irq
,
&
wdtpci_miscdev
);
release_region
(
io
,
16
);
pci_release_region
(
pdev
,
2
);
pci_disable_device
(
pdev
);
dev_count
--
;
}
...
...
drivers/watchdog/wm831x_wdt.c
0 → 100644
View file @
ae735d7c
/*
* Watchdog driver for the wm831x PMICs
*
* Copyright (C) 2009 Wolfson Microelectronics
*
* 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
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/watchdog.h>
static
int
nowayout
=
WATCHDOG_NOWAYOUT
;
module_param
(
nowayout
,
int
,
0
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING
(
WATCHDOG_NOWAYOUT
)
")"
);
static
unsigned
long
wm831x_wdt_users
;
static
struct
miscdevice
wm831x_wdt_miscdev
;
static
int
wm831x_wdt_expect_close
;
static
DEFINE_MUTEX
(
wdt_mutex
);
static
struct
wm831x
*
wm831x
;
static
unsigned
int
update_gpio
;
static
unsigned
int
update_state
;
/* We can't use the sub-second values here but they're included
* for completeness. */
static
struct
{
int
time
;
/* Seconds */
u16
val
;
/* WDOG_TO value */
}
wm831x_wdt_cfgs
[]
=
{
{
1
,
2
},
{
2
,
3
},
{
4
,
4
},
{
8
,
5
},
{
16
,
6
},
{
32
,
7
},
{
33
,
7
},
/* Actually 32.768s so include both, others round down */
};
static
int
wm831x_wdt_set_timeout
(
struct
wm831x
*
wm831x
,
u16
value
)
{
int
ret
;
mutex_lock
(
&
wdt_mutex
);
ret
=
wm831x_reg_unlock
(
wm831x
);
if
(
ret
==
0
)
{
ret
=
wm831x_set_bits
(
wm831x
,
WM831X_WATCHDOG
,
WM831X_WDOG_TO_MASK
,
value
);
wm831x_reg_lock
(
wm831x
);
}
else
{
dev_err
(
wm831x
->
dev
,
"Failed to unlock security key: %d
\n
"
,
ret
);
}
mutex_unlock
(
&
wdt_mutex
);
return
ret
;
}
static
int
wm831x_wdt_start
(
struct
wm831x
*
wm831x
)
{
int
ret
;
mutex_lock
(
&
wdt_mutex
);
ret
=
wm831x_reg_unlock
(
wm831x
);
if
(
ret
==
0
)
{
ret
=
wm831x_set_bits
(
wm831x
,
WM831X_WATCHDOG
,
WM831X_WDOG_ENA
,
WM831X_WDOG_ENA
);
wm831x_reg_lock
(
wm831x
);
}
else
{
dev_err
(
wm831x
->
dev
,
"Failed to unlock security key: %d
\n
"
,
ret
);
}
mutex_unlock
(
&
wdt_mutex
);
return
ret
;
}
static
int
wm831x_wdt_stop
(
struct
wm831x
*
wm831x
)
{
int
ret
;
mutex_lock
(
&
wdt_mutex
);
ret
=
wm831x_reg_unlock
(
wm831x
);
if
(
ret
==
0
)
{
ret
=
wm831x_set_bits
(
wm831x
,
WM831X_WATCHDOG
,
WM831X_WDOG_ENA
,
0
);
wm831x_reg_lock
(
wm831x
);
}
else
{
dev_err
(
wm831x
->
dev
,
"Failed to unlock security key: %d
\n
"
,
ret
);
}
mutex_unlock
(
&
wdt_mutex
);
return
ret
;
}
static
int
wm831x_wdt_kick
(
struct
wm831x
*
wm831x
)
{
int
ret
;
u16
reg
;
mutex_lock
(
&
wdt_mutex
);
if
(
update_gpio
)
{
gpio_set_value_cansleep
(
update_gpio
,
update_state
);
update_state
=
!
update_state
;
ret
=
0
;
goto
out
;
}
reg
=
wm831x_reg_read
(
wm831x
,
WM831X_WATCHDOG
);
if
(
!
(
reg
&
WM831X_WDOG_RST_SRC
))
{
dev_err
(
wm831x
->
dev
,
"Hardware watchdog update unsupported
\n
"
);
ret
=
-
EINVAL
;
goto
out
;
}
reg
|=
WM831X_WDOG_RESET
;
ret
=
wm831x_reg_unlock
(
wm831x
);
if
(
ret
==
0
)
{
ret
=
wm831x_reg_write
(
wm831x
,
WM831X_WATCHDOG
,
reg
);
wm831x_reg_lock
(
wm831x
);
}
else
{
dev_err
(
wm831x
->
dev
,
"Failed to unlock security key: %d
\n
"
,
ret
);
}
out:
mutex_unlock
(
&
wdt_mutex
);
return
ret
;
}
static
int
wm831x_wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
ret
;
if
(
!
wm831x
)
return
-
ENODEV
;
if
(
test_and_set_bit
(
0
,
&
wm831x_wdt_users
))
return
-
EBUSY
;
ret
=
wm831x_wdt_start
(
wm831x
);
if
(
ret
!=
0
)
return
ret
;
return
nonseekable_open
(
inode
,
file
);
}
static
int
wm831x_wdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
wm831x_wdt_expect_close
)
wm831x_wdt_stop
(
wm831x
);
else
{
dev_warn
(
wm831x
->
dev
,
"Watchdog device closed uncleanly
\n
"
);
wm831x_wdt_kick
(
wm831x
);
}
clear_bit
(
0
,
&
wm831x_wdt_users
);
return
0
;
}
static
ssize_t
wm831x_wdt_write
(
struct
file
*
file
,
const
char
__user
*
data
,
size_t
count
,
loff_t
*
ppos
)
{
size_t
i
;
if
(
count
)
{
wm831x_wdt_kick
(
wm831x
);
if
(
!
nowayout
)
{
/* In case it was set long ago */
wm831x_wdt_expect_close
=
0
;
/* scan to see whether or not we got the magic
character */
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
wm831x_wdt_expect_close
=
42
;
}
}
}
return
count
;
}
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
identity
=
"WM831x Watchdog"
,
};
static
long
wm831x_wdt_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
ret
=
-
ENOTTY
,
time
,
i
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
__user
*
p
=
argp
;
u16
reg
;
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
ret
=
copy_to_user
(
argp
,
&
ident
,
sizeof
(
ident
))
?
-
EFAULT
:
0
;
break
;
case
WDIOC_GETSTATUS
:
case
WDIOC_GETBOOTSTATUS
:
ret
=
put_user
(
0
,
p
);
break
;
case
WDIOC_SETOPTIONS
:
{
int
options
;
if
(
get_user
(
options
,
p
))
return
-
EFAULT
;
ret
=
-
EINVAL
;
/* Setting both simultaneously means at least one must fail */
if
(
options
==
WDIOS_DISABLECARD
)
ret
=
wm831x_wdt_start
(
wm831x
);
if
(
options
==
WDIOS_ENABLECARD
)
ret
=
wm831x_wdt_stop
(
wm831x
);
break
;
}
case
WDIOC_KEEPALIVE
:
ret
=
wm831x_wdt_kick
(
wm831x
);
break
;
case
WDIOC_SETTIMEOUT
:
ret
=
get_user
(
time
,
p
);
if
(
ret
)
break
;
if
(
time
==
0
)
{
if
(
nowayout
)
ret
=
-
EINVAL
;
else
wm831x_wdt_stop
(
wm831x
);
break
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm831x_wdt_cfgs
);
i
++
)
if
(
wm831x_wdt_cfgs
[
i
].
time
==
time
)
break
;
if
(
i
==
ARRAY_SIZE
(
wm831x_wdt_cfgs
))
ret
=
-
EINVAL
;
else
ret
=
wm831x_wdt_set_timeout
(
wm831x
,
wm831x_wdt_cfgs
[
i
].
val
);
break
;
case
WDIOC_GETTIMEOUT
:
reg
=
wm831x_reg_read
(
wm831x
,
WM831X_WATCHDOG
);
reg
&=
WM831X_WDOG_TO_MASK
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm831x_wdt_cfgs
);
i
++
)
if
(
wm831x_wdt_cfgs
[
i
].
val
==
reg
)
break
;
if
(
i
==
ARRAY_SIZE
(
wm831x_wdt_cfgs
))
{
dev_warn
(
wm831x
->
dev
,
"Unknown watchdog configuration: %x
\n
"
,
reg
);
ret
=
-
EINVAL
;
}
else
ret
=
put_user
(
wm831x_wdt_cfgs
[
i
].
time
,
p
);
}
return
ret
;
}
static
const
struct
file_operations
wm831x_wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
wm831x_wdt_write
,
.
unlocked_ioctl
=
wm831x_wdt_ioctl
,
.
open
=
wm831x_wdt_open
,
.
release
=
wm831x_wdt_release
,
};
static
struct
miscdevice
wm831x_wdt_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
wm831x_wdt_fops
,
};
static
int
__devinit
wm831x_wdt_probe
(
struct
platform_device
*
pdev
)
{
struct
wm831x_pdata
*
chip_pdata
;
struct
wm831x_watchdog_pdata
*
pdata
;
int
reg
,
ret
;
wm831x
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
ret
=
wm831x_reg_read
(
wm831x
,
WM831X_WATCHDOG
);
if
(
ret
<
0
)
{
dev_err
(
wm831x
->
dev
,
"Failed to read watchdog status: %d
\n
"
,
ret
);
goto
err
;
}
reg
=
ret
;
if
(
reg
&
WM831X_WDOG_DEBUG
)
dev_warn
(
wm831x
->
dev
,
"Watchdog is paused
\n
"
);
/* Apply any configuration */
if
(
pdev
->
dev
.
parent
->
platform_data
)
{
chip_pdata
=
pdev
->
dev
.
parent
->
platform_data
;
pdata
=
chip_pdata
->
watchdog
;
}
else
{
pdata
=
NULL
;
}
if
(
pdata
)
{
reg
&=
~
(
WM831X_WDOG_SECACT_MASK
|
WM831X_WDOG_PRIMACT_MASK
|
WM831X_WDOG_RST_SRC
);
reg
|=
pdata
->
primary
<<
WM831X_WDOG_PRIMACT_SHIFT
;
reg
|=
pdata
->
secondary
<<
WM831X_WDOG_SECACT_SHIFT
;
reg
|=
pdata
->
software
<<
WM831X_WDOG_RST_SRC_SHIFT
;
if
(
pdata
->
update_gpio
)
{
ret
=
gpio_request
(
pdata
->
update_gpio
,
"Watchdog update"
);
if
(
ret
<
0
)
{
dev_err
(
wm831x
->
dev
,
"Failed to request update GPIO: %d
\n
"
,
ret
);
goto
err
;
}
ret
=
gpio_direction_output
(
pdata
->
update_gpio
,
0
);
if
(
ret
!=
0
)
{
dev_err
(
wm831x
->
dev
,
"gpio_direction_output returned: %d
\n
"
,
ret
);
goto
err_gpio
;
}
update_gpio
=
pdata
->
update_gpio
;
/* Make sure the watchdog takes hardware updates */
reg
|=
WM831X_WDOG_RST_SRC
;
}
ret
=
wm831x_reg_unlock
(
wm831x
);
if
(
ret
==
0
)
{
ret
=
wm831x_reg_write
(
wm831x
,
WM831X_WATCHDOG
,
reg
);
wm831x_reg_lock
(
wm831x
);
}
else
{
dev_err
(
wm831x
->
dev
,
"Failed to unlock security key: %d
\n
"
,
ret
);
goto
err_gpio
;
}
}
wm831x_wdt_miscdev
.
parent
=
&
pdev
->
dev
;
ret
=
misc_register
(
&
wm831x_wdt_miscdev
);
if
(
ret
!=
0
)
{
dev_err
(
wm831x
->
dev
,
"Failed to register miscdev: %d
\n
"
,
ret
);
goto
err_gpio
;
}
return
0
;
err_gpio:
if
(
update_gpio
)
{
gpio_free
(
update_gpio
);
update_gpio
=
0
;
}
err:
return
ret
;
}
static
int
__devexit
wm831x_wdt_remove
(
struct
platform_device
*
pdev
)
{
if
(
update_gpio
)
{
gpio_free
(
update_gpio
);
update_gpio
=
0
;
}
misc_deregister
(
&
wm831x_wdt_miscdev
);
return
0
;
}
static
struct
platform_driver
wm831x_wdt_driver
=
{
.
probe
=
wm831x_wdt_probe
,
.
remove
=
__devexit_p
(
wm831x_wdt_remove
),
.
driver
=
{
.
name
=
"wm831x-watchdog"
,
},
};
static
int
__init
wm831x_wdt_init
(
void
)
{
return
platform_driver_register
(
&
wm831x_wdt_driver
);
}
module_init
(
wm831x_wdt_init
);
static
void
__exit
wm831x_wdt_exit
(
void
)
{
platform_driver_unregister
(
&
wm831x_wdt_driver
);
}
module_exit
(
wm831x_wdt_exit
);
MODULE_AUTHOR
(
"Mark Brown"
);
MODULE_DESCRIPTION
(
"WM831x Watchdog"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:wm831x-watchdog"
);
include/linux/mfd/wm831x/watchdog.h
0 → 100644
View file @
ae735d7c
/*
* include/linux/mfd/wm831x/watchdog.h -- Watchdog for WM831x
*
* Copyright 2009 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.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; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __MFD_WM831X_WATCHDOG_H__
#define __MFD_WM831X_WATCHDOG_H__
/*
* R16388 (0x4004) - Watchdog
*/
#define WM831X_WDOG_ENA 0x8000
/* WDOG_ENA */
#define WM831X_WDOG_ENA_MASK 0x8000
/* WDOG_ENA */
#define WM831X_WDOG_ENA_SHIFT 15
/* WDOG_ENA */
#define WM831X_WDOG_ENA_WIDTH 1
/* WDOG_ENA */
#define WM831X_WDOG_DEBUG 0x4000
/* WDOG_DEBUG */
#define WM831X_WDOG_DEBUG_MASK 0x4000
/* WDOG_DEBUG */
#define WM831X_WDOG_DEBUG_SHIFT 14
/* WDOG_DEBUG */
#define WM831X_WDOG_DEBUG_WIDTH 1
/* WDOG_DEBUG */
#define WM831X_WDOG_RST_SRC 0x2000
/* WDOG_RST_SRC */
#define WM831X_WDOG_RST_SRC_MASK 0x2000
/* WDOG_RST_SRC */
#define WM831X_WDOG_RST_SRC_SHIFT 13
/* WDOG_RST_SRC */
#define WM831X_WDOG_RST_SRC_WIDTH 1
/* WDOG_RST_SRC */
#define WM831X_WDOG_SLPENA 0x1000
/* WDOG_SLPENA */
#define WM831X_WDOG_SLPENA_MASK 0x1000
/* WDOG_SLPENA */
#define WM831X_WDOG_SLPENA_SHIFT 12
/* WDOG_SLPENA */
#define WM831X_WDOG_SLPENA_WIDTH 1
/* WDOG_SLPENA */
#define WM831X_WDOG_RESET 0x0800
/* WDOG_RESET */
#define WM831X_WDOG_RESET_MASK 0x0800
/* WDOG_RESET */
#define WM831X_WDOG_RESET_SHIFT 11
/* WDOG_RESET */
#define WM831X_WDOG_RESET_WIDTH 1
/* WDOG_RESET */
#define WM831X_WDOG_SECACT_MASK 0x0300
/* WDOG_SECACT - [9:8] */
#define WM831X_WDOG_SECACT_SHIFT 8
/* WDOG_SECACT - [9:8] */
#define WM831X_WDOG_SECACT_WIDTH 2
/* WDOG_SECACT - [9:8] */
#define WM831X_WDOG_PRIMACT_MASK 0x0030
/* WDOG_PRIMACT - [5:4] */
#define WM831X_WDOG_PRIMACT_SHIFT 4
/* WDOG_PRIMACT - [5:4] */
#define WM831X_WDOG_PRIMACT_WIDTH 2
/* WDOG_PRIMACT - [5:4] */
#define WM831X_WDOG_TO_MASK 0x0007
/* WDOG_TO - [2:0] */
#define WM831X_WDOG_TO_SHIFT 0
/* WDOG_TO - [2:0] */
#define WM831X_WDOG_TO_WIDTH 3
/* WDOG_TO - [2:0] */
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment