2008-06-26 12:47:45 +04:00
/*
2009-06-01 21:56:02 +04:00
* drivers / watchdog / orion_wdt . c
2008-06-26 12:47:45 +04:00
*
2009-06-01 21:56:02 +04:00
* Watchdog driver for Orion / Kirkwood processors
2008-06-26 12:47:45 +04:00
*
* Author : Sylver Bruneau < sylver . bruneau @ googlemail . com >
*
* 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 .
*/
2012-02-16 03:06:19 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-06-26 12:47:45 +04:00
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/types.h>
# include <linux/kernel.h>
2009-02-25 01:59:22 +03:00
# include <linux/platform_device.h>
2008-06-26 12:47:45 +04:00
# include <linux/watchdog.h>
2014-02-11 03:00:24 +04:00
# include <linux/interrupt.h>
2008-06-26 12:47:45 +04:00
# include <linux/io.h>
2012-03-04 19:57:31 +04:00
# include <linux/clk.h>
2012-03-26 07:14:29 +04:00
# include <linux/err.h>
2012-06-10 17:20:06 +04:00
# include <linux/of.h>
2014-02-11 03:00:28 +04:00
# include <linux/of_device.h>
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:25 +04:00
/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
# define ORION_RSTOUT_MASK_OFFSET 0x20108
/* Internal registers can be configured at any 1 MiB aligned address */
# define INTERNAL_REGS_MASK ~(SZ_1M - 1)
2008-06-26 12:47:45 +04:00
/*
* Watchdog timer block registers .
*/
2012-03-15 04:33:26 +04:00
# define TIMER_CTRL 0x0000
2019-08-30 00:52:24 +03:00
# define TIMER1_FIXED_ENABLE_BIT BIT(12)
# define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
# define TIMER1_ENABLE_BIT BIT(2)
# define TIMER_A370_STATUS 0x0004
# define WDT_A370_EXPIRED BIT(31)
# define TIMER1_STATUS_BIT BIT(8)
# define TIMER1_VAL_OFF 0x001c
2008-06-26 12:47:45 +04:00
2009-02-25 01:59:22 +03:00
# define WDT_MAX_CYCLE_COUNT 0xffffffff
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:31 +04:00
# define WDT_A370_RATIO_MASK(v) ((v) << 16)
# define WDT_A370_RATIO_SHIFT 5
# define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT)
2012-03-05 19:51:11 +04:00
static bool nowayout = WATCHDOG_NOWAYOUT ;
2020-03-13 06:13:12 +03:00
static int heartbeat ; /* module parameter (seconds) */
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:29 +04:00
struct orion_watchdog ;
2014-02-11 03:00:28 +04:00
struct orion_watchdog_data {
int wdt_counter_offset ;
int wdt_enable_bit ;
int rstout_enable_bit ;
2014-03-15 22:18:01 +04:00
int rstout_mask_bit ;
2014-02-11 03:00:29 +04:00
int ( * clock_init ) ( struct platform_device * ,
struct orion_watchdog * ) ;
2014-03-15 22:18:00 +04:00
int ( * enabled ) ( struct orion_watchdog * ) ;
2014-02-11 03:00:30 +04:00
int ( * start ) ( struct watchdog_device * ) ;
2014-03-15 22:17:59 +04:00
int ( * stop ) ( struct watchdog_device * ) ;
2014-02-11 03:00:28 +04:00
} ;
2014-02-11 03:00:27 +04:00
struct orion_watchdog {
struct watchdog_device wdt ;
void __iomem * reg ;
void __iomem * rstout ;
2014-03-15 22:18:01 +04:00
void __iomem * rstout_mask ;
2014-02-11 03:00:27 +04:00
unsigned long clk_rate ;
struct clk * clk ;
2014-02-11 03:00:28 +04:00
const struct orion_watchdog_data * data ;
2014-02-11 03:00:27 +04:00
} ;
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:29 +04:00
static int orion_wdt_clock_init ( struct platform_device * pdev ,
struct orion_watchdog * dev )
2009-02-20 21:44:59 +03:00
{
2014-02-11 03:00:29 +04:00
int ret ;
2009-02-20 21:44:59 +03:00
2014-02-11 03:00:31 +04:00
dev - > clk = clk_get ( & pdev - > dev , NULL ) ;
2014-02-11 03:00:29 +04:00
if ( IS_ERR ( dev - > clk ) )
return PTR_ERR ( dev - > clk ) ;
ret = clk_prepare_enable ( dev - > clk ) ;
2014-02-11 03:00:31 +04:00
if ( ret ) {
clk_put ( dev - > clk ) ;
2014-02-11 03:00:29 +04:00
return ret ;
2014-02-11 03:00:31 +04:00
}
2009-02-20 21:44:59 +03:00
2014-02-11 03:00:31 +04:00
dev - > clk_rate = clk_get_rate ( dev - > clk ) ;
2012-03-26 07:14:29 +04:00
return 0 ;
2009-02-20 21:44:59 +03:00
}
2014-02-11 03:00:31 +04:00
static int armada370_wdt_clock_init ( struct platform_device * pdev ,
struct orion_watchdog * dev )
2008-06-26 12:47:45 +04:00
{
2014-02-11 03:00:31 +04:00
int ret ;
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:31 +04:00
dev - > clk = clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( dev - > clk ) )
return PTR_ERR ( dev - > clk ) ;
ret = clk_prepare_enable ( dev - > clk ) ;
if ( ret ) {
clk_put ( dev - > clk ) ;
return ret ;
}
/* Setup watchdog input clock */
atomic_io_modify ( dev - > reg + TIMER_CTRL ,
WDT_A370_RATIO_MASK ( WDT_A370_RATIO_SHIFT ) ,
WDT_A370_RATIO_MASK ( WDT_A370_RATIO_SHIFT ) ) ;
dev - > clk_rate = clk_get_rate ( dev - > clk ) / WDT_A370_RATIO ;
return 0 ;
}
2014-11-04 16:21:32 +03:00
static int armada375_wdt_clock_init ( struct platform_device * pdev ,
struct orion_watchdog * dev )
{
int ret ;
dev - > clk = of_clk_get_by_name ( pdev - > dev . of_node , " fixed " ) ;
if ( ! IS_ERR ( dev - > clk ) ) {
ret = clk_prepare_enable ( dev - > clk ) ;
if ( ret ) {
clk_put ( dev - > clk ) ;
return ret ;
}
atomic_io_modify ( dev - > reg + TIMER_CTRL ,
WDT_AXP_FIXED_ENABLE_BIT ,
WDT_AXP_FIXED_ENABLE_BIT ) ;
dev - > clk_rate = clk_get_rate ( dev - > clk ) ;
return 0 ;
}
/* Mandatory fallback for proper devicetree backward compatibility */
dev - > clk = clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( dev - > clk ) )
return PTR_ERR ( dev - > clk ) ;
ret = clk_prepare_enable ( dev - > clk ) ;
if ( ret ) {
clk_put ( dev - > clk ) ;
return ret ;
}
atomic_io_modify ( dev - > reg + TIMER_CTRL ,
WDT_A370_RATIO_MASK ( WDT_A370_RATIO_SHIFT ) ,
WDT_A370_RATIO_MASK ( WDT_A370_RATIO_SHIFT ) ) ;
dev - > clk_rate = clk_get_rate ( dev - > clk ) / WDT_A370_RATIO ;
return 0 ;
}
2014-02-11 03:00:31 +04:00
static int armadaxp_wdt_clock_init ( struct platform_device * pdev ,
struct orion_watchdog * dev )
{
int ret ;
2019-08-30 00:52:24 +03:00
u32 val ;
2014-02-11 03:00:31 +04:00
dev - > clk = of_clk_get_by_name ( pdev - > dev . of_node , " fixed " ) ;
if ( IS_ERR ( dev - > clk ) )
return PTR_ERR ( dev - > clk ) ;
ret = clk_prepare_enable ( dev - > clk ) ;
if ( ret ) {
clk_put ( dev - > clk ) ;
return ret ;
}
2019-08-30 00:52:24 +03:00
/* Fix the wdt and timer1 clock freqency to 25MHz */
val = WDT_AXP_FIXED_ENABLE_BIT | TIMER1_FIXED_ENABLE_BIT ;
atomic_io_modify ( dev - > reg + TIMER_CTRL , val , val ) ;
2014-02-11 03:00:29 +04:00
dev - > clk_rate = clk_get_rate ( dev - > clk ) ;
return 0 ;
}
2012-03-26 07:14:29 +04:00
static int orion_wdt_ping ( struct watchdog_device * wdt_dev )
2009-02-20 21:44:59 +03:00
{
2014-02-11 03:00:27 +04:00
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
2009-02-20 21:44:59 +03:00
/* Reload watchdog duration */
2014-02-11 03:00:28 +04:00
writel ( dev - > clk_rate * wdt_dev - > timeout ,
dev - > reg + dev - > data - > wdt_counter_offset ) ;
2019-08-30 00:52:24 +03:00
if ( dev - > wdt . info - > options & WDIOF_PRETIMEOUT )
writel ( dev - > clk_rate * ( wdt_dev - > timeout - wdt_dev - > pretimeout ) ,
dev - > reg + TIMER1_VAL_OFF ) ;
2012-03-26 07:14:29 +04:00
return 0 ;
2009-02-20 21:44:59 +03:00
}
2014-03-15 22:18:01 +04:00
static int armada375_start ( struct watchdog_device * wdt_dev )
{
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
u32 reg ;
/* Set watchdog duration */
writel ( dev - > clk_rate * wdt_dev - > timeout ,
dev - > reg + dev - > data - > wdt_counter_offset ) ;
2019-08-30 00:52:24 +03:00
if ( dev - > wdt . info - > options & WDIOF_PRETIMEOUT )
writel ( dev - > clk_rate * ( wdt_dev - > timeout - wdt_dev - > pretimeout ) ,
dev - > reg + TIMER1_VAL_OFF ) ;
2014-03-15 22:18:01 +04:00
/* Clear the watchdog expiration bit */
atomic_io_modify ( dev - > reg + TIMER_A370_STATUS , WDT_A370_EXPIRED , 0 ) ;
/* Enable watchdog timer */
2019-08-30 00:52:24 +03:00
reg = dev - > data - > wdt_enable_bit ;
if ( dev - > wdt . info - > options & WDIOF_PRETIMEOUT )
reg | = TIMER1_ENABLE_BIT ;
atomic_io_modify ( dev - > reg + TIMER_CTRL , reg , reg ) ;
2014-03-15 22:18:01 +04:00
/* Enable reset on watchdog */
reg = readl ( dev - > rstout ) ;
reg | = dev - > data - > rstout_enable_bit ;
writel ( reg , dev - > rstout ) ;
atomic_io_modify ( dev - > rstout_mask , dev - > data - > rstout_mask_bit , 0 ) ;
return 0 ;
}
2014-02-11 03:00:31 +04:00
static int armada370_start ( struct watchdog_device * wdt_dev )
{
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
2014-03-15 22:17:58 +04:00
u32 reg ;
2008-10-02 13:32:45 +04:00
2008-06-26 12:47:45 +04:00
/* Set watchdog duration */
2014-02-11 03:00:31 +04:00
writel ( dev - > clk_rate * wdt_dev - > timeout ,
dev - > reg + dev - > data - > wdt_counter_offset ) ;
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:31 +04:00
/* Clear the watchdog expiration bit */
atomic_io_modify ( dev - > reg + TIMER_A370_STATUS , WDT_A370_EXPIRED , 0 ) ;
2008-06-26 12:47:45 +04:00
/* Enable watchdog timer */
2014-02-11 03:00:31 +04:00
atomic_io_modify ( dev - > reg + TIMER_CTRL , dev - > data - > wdt_enable_bit ,
dev - > data - > wdt_enable_bit ) ;
2014-03-15 22:17:58 +04:00
/* Enable reset on watchdog */
reg = readl ( dev - > rstout ) ;
reg | = dev - > data - > rstout_enable_bit ;
writel ( reg , dev - > rstout ) ;
2014-02-11 03:00:31 +04:00
return 0 ;
}
2014-02-11 03:00:30 +04:00
static int orion_start ( struct watchdog_device * wdt_dev )
2008-06-26 12:47:45 +04:00
{
2014-02-11 03:00:27 +04:00
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
2008-06-26 12:47:45 +04:00
/* Set watchdog duration */
2014-02-11 03:00:28 +04:00
writel ( dev - > clk_rate * wdt_dev - > timeout ,
dev - > reg + dev - > data - > wdt_counter_offset ) ;
2008-06-26 12:47:45 +04:00
/* Enable watchdog timer */
2014-02-11 03:00:28 +04:00
atomic_io_modify ( dev - > reg + TIMER_CTRL , dev - > data - > wdt_enable_bit ,
dev - > data - > wdt_enable_bit ) ;
2008-06-26 12:47:45 +04:00
/* Enable reset on watchdog */
2014-02-11 03:00:28 +04:00
atomic_io_modify ( dev - > rstout , dev - > data - > rstout_enable_bit ,
dev - > data - > rstout_enable_bit ) ;
2008-10-02 13:32:45 +04:00
2012-03-26 07:14:29 +04:00
return 0 ;
2008-06-26 12:47:45 +04:00
}
2014-02-11 03:00:30 +04:00
static int orion_wdt_start ( struct watchdog_device * wdt_dev )
2008-06-26 12:47:45 +04:00
{
2014-02-11 03:00:30 +04:00
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:30 +04:00
/* There are some per-SoC quirks to handle */
return dev - > data - > start ( wdt_dev ) ;
}
2014-03-15 22:17:59 +04:00
static int orion_stop ( struct watchdog_device * wdt_dev )
2008-06-26 12:47:45 +04:00
{
2014-02-11 03:00:27 +04:00
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
2008-10-02 13:32:45 +04:00
2008-06-26 12:47:45 +04:00
/* Disable reset on watchdog */
2014-02-11 03:00:28 +04:00
atomic_io_modify ( dev - > rstout , dev - > data - > rstout_enable_bit , 0 ) ;
2008-06-26 12:47:45 +04:00
/* Disable watchdog timer */
2014-02-11 03:00:28 +04:00
atomic_io_modify ( dev - > reg + TIMER_CTRL , dev - > data - > wdt_enable_bit , 0 ) ;
2008-10-02 13:32:45 +04:00
2012-03-26 07:14:29 +04:00
return 0 ;
2008-10-02 13:32:45 +04:00
}
2014-03-15 22:18:01 +04:00
static int armada375_stop ( struct watchdog_device * wdt_dev )
{
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
2019-08-30 00:52:24 +03:00
u32 reg , mask ;
2014-03-15 22:18:01 +04:00
/* Disable reset on watchdog */
atomic_io_modify ( dev - > rstout_mask , dev - > data - > rstout_mask_bit ,
dev - > data - > rstout_mask_bit ) ;
reg = readl ( dev - > rstout ) ;
reg & = ~ dev - > data - > rstout_enable_bit ;
writel ( reg , dev - > rstout ) ;
/* Disable watchdog timer */
2019-08-30 00:52:24 +03:00
mask = dev - > data - > wdt_enable_bit ;
if ( wdt_dev - > info - > options & WDIOF_PRETIMEOUT )
mask | = TIMER1_ENABLE_BIT ;
atomic_io_modify ( dev - > reg + TIMER_CTRL , mask , 0 ) ;
2014-03-15 22:18:01 +04:00
return 0 ;
}
2014-03-15 22:17:59 +04:00
static int armada370_stop ( struct watchdog_device * wdt_dev )
{
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
u32 reg ;
/* Disable reset on watchdog */
reg = readl ( dev - > rstout ) ;
reg & = ~ dev - > data - > rstout_enable_bit ;
writel ( reg , dev - > rstout ) ;
/* Disable watchdog timer */
atomic_io_modify ( dev - > reg + TIMER_CTRL , dev - > data - > wdt_enable_bit , 0 ) ;
return 0 ;
}
static int orion_wdt_stop ( struct watchdog_device * wdt_dev )
{
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
return dev - > data - > stop ( wdt_dev ) ;
}
2014-03-15 22:18:00 +04:00
static int orion_enabled ( struct orion_watchdog * dev )
2008-10-02 13:32:45 +04:00
{
2014-02-11 03:00:23 +04:00
bool enabled , running ;
2014-02-11 03:00:28 +04:00
enabled = readl ( dev - > rstout ) & dev - > data - > rstout_enable_bit ;
running = readl ( dev - > reg + TIMER_CTRL ) & dev - > data - > wdt_enable_bit ;
2012-03-26 07:14:29 +04:00
2014-02-11 03:00:23 +04:00
return enabled & & running ;
}
2008-06-26 12:47:45 +04:00
2014-03-15 22:18:01 +04:00
static int armada375_enabled ( struct orion_watchdog * dev )
{
bool masked , enabled , running ;
masked = readl ( dev - > rstout_mask ) & dev - > data - > rstout_mask_bit ;
enabled = readl ( dev - > rstout ) & dev - > data - > rstout_enable_bit ;
running = readl ( dev - > reg + TIMER_CTRL ) & dev - > data - > wdt_enable_bit ;
return ! masked & & enabled & & running ;
}
2014-03-15 22:18:00 +04:00
static int orion_wdt_enabled ( struct watchdog_device * wdt_dev )
{
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
return dev - > data - > enabled ( dev ) ;
}
2012-03-26 07:14:29 +04:00
static unsigned int orion_wdt_get_timeleft ( struct watchdog_device * wdt_dev )
2008-10-02 13:32:45 +04:00
{
2014-02-11 03:00:27 +04:00
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
2014-02-11 03:00:28 +04:00
return readl ( dev - > reg + dev - > data - > wdt_counter_offset ) / dev - > clk_rate ;
2008-06-26 12:47:45 +04:00
}
2019-08-30 00:52:24 +03:00
static struct watchdog_info orion_wdt_info = {
2012-03-26 07:14:29 +04:00
. options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE ,
. identity = " Orion Watchdog " ,
2008-06-26 12:47:45 +04:00
} ;
2012-03-26 07:14:29 +04:00
static const struct watchdog_ops orion_wdt_ops = {
. owner = THIS_MODULE ,
. start = orion_wdt_start ,
. stop = orion_wdt_stop ,
. ping = orion_wdt_ping ,
. get_timeleft = orion_wdt_get_timeleft ,
2008-06-26 12:47:45 +04:00
} ;
2014-02-11 03:00:24 +04:00
static irqreturn_t orion_wdt_irq ( int irq , void * devid )
{
panic ( " Watchdog Timeout " ) ;
return IRQ_HANDLED ;
}
2019-08-30 00:52:24 +03:00
static irqreturn_t orion_wdt_pre_irq ( int irq , void * devid )
{
struct orion_watchdog * dev = devid ;
atomic_io_modify ( dev - > reg + TIMER_A370_STATUS ,
TIMER1_STATUS_BIT , 0 ) ;
watchdog_notify_pretimeout ( & dev - > wdt ) ;
return IRQ_HANDLED ;
}
2014-02-11 03:00:25 +04:00
/*
* The original devicetree binding for this driver specified only
* one memory resource , so in order to keep DT backwards compatibility
* we try to fallback to a hardcoded register address , if the resource
* is missing from the devicetree .
*/
static void __iomem * orion_wdt_ioremap_rstout ( struct platform_device * pdev ,
phys_addr_t internal_regs )
{
struct resource * res ;
phys_addr_t rstout ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
if ( res )
return devm_ioremap ( & pdev - > dev , res - > start ,
resource_size ( res ) ) ;
rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET ;
2016-12-30 00:49:18 +03:00
WARN ( 1 , FW_BUG " falling back to hardcoded RSTOUT reg %pa \n " , & rstout ) ;
2014-02-11 03:00:25 +04:00
return devm_ioremap ( & pdev - > dev , rstout , 0x4 ) ;
}
2014-02-11 03:00:28 +04:00
static const struct orion_watchdog_data orion_data = {
. rstout_enable_bit = BIT ( 1 ) ,
. wdt_enable_bit = BIT ( 4 ) ,
. wdt_counter_offset = 0x24 ,
2014-02-11 03:00:29 +04:00
. clock_init = orion_wdt_clock_init ,
2014-03-15 22:18:00 +04:00
. enabled = orion_enabled ,
2014-02-11 03:00:30 +04:00
. start = orion_start ,
2014-03-15 22:17:59 +04:00
. stop = orion_stop ,
2014-02-11 03:00:28 +04:00
} ;
2014-02-11 03:00:31 +04:00
static const struct orion_watchdog_data armada370_data = {
. rstout_enable_bit = BIT ( 8 ) ,
. wdt_enable_bit = BIT ( 8 ) ,
. wdt_counter_offset = 0x34 ,
. clock_init = armada370_wdt_clock_init ,
2014-03-15 22:18:00 +04:00
. enabled = orion_enabled ,
2014-02-11 03:00:31 +04:00
. start = armada370_start ,
2014-03-15 22:17:59 +04:00
. stop = armada370_stop ,
2008-06-26 12:47:45 +04:00
} ;
2014-02-11 03:00:31 +04:00
static const struct orion_watchdog_data armadaxp_data = {
. rstout_enable_bit = BIT ( 8 ) ,
. wdt_enable_bit = BIT ( 8 ) ,
. wdt_counter_offset = 0x34 ,
. clock_init = armadaxp_wdt_clock_init ,
2014-03-15 22:18:00 +04:00
. enabled = orion_enabled ,
2014-02-11 03:00:31 +04:00
. start = armada370_start ,
2014-03-15 22:17:59 +04:00
. stop = armada370_stop ,
2014-02-11 03:00:31 +04:00
} ;
2014-03-15 22:18:01 +04:00
static const struct orion_watchdog_data armada375_data = {
. rstout_enable_bit = BIT ( 8 ) ,
. rstout_mask_bit = BIT ( 10 ) ,
. wdt_enable_bit = BIT ( 8 ) ,
. wdt_counter_offset = 0x34 ,
2014-11-04 16:21:32 +03:00
. clock_init = armada375_wdt_clock_init ,
2014-03-15 22:18:01 +04:00
. enabled = armada375_enabled ,
. start = armada375_start ,
. stop = armada375_stop ,
} ;
static const struct orion_watchdog_data armada380_data = {
. rstout_enable_bit = BIT ( 8 ) ,
. rstout_mask_bit = BIT ( 10 ) ,
. wdt_enable_bit = BIT ( 8 ) ,
. wdt_counter_offset = 0x34 ,
. clock_init = armadaxp_wdt_clock_init ,
. enabled = armada375_enabled ,
. start = armada375_start ,
. stop = armada375_stop ,
} ;
2014-02-11 03:00:28 +04:00
static const struct of_device_id orion_wdt_of_match_table [ ] = {
{
. compatible = " marvell,orion-wdt " ,
. data = & orion_data ,
} ,
2014-02-11 03:00:31 +04:00
{
. compatible = " marvell,armada-370-wdt " ,
. data = & armada370_data ,
} ,
{
. compatible = " marvell,armada-xp-wdt " ,
. data = & armadaxp_data ,
} ,
2014-03-15 22:18:01 +04:00
{
. compatible = " marvell,armada-375-wdt " ,
. data = & armada375_data ,
} ,
{
. compatible = " marvell,armada-380-wdt " ,
. data = & armada380_data ,
} ,
2014-02-11 03:00:28 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , orion_wdt_of_match_table ) ;
2014-03-15 22:17:56 +04:00
static int orion_wdt_get_regs ( struct platform_device * pdev ,
struct orion_watchdog * dev )
{
2014-03-15 22:17:57 +04:00
struct device_node * node = pdev - > dev . of_node ;
2014-03-15 22:17:56 +04:00
struct resource * res ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - ENODEV ;
dev - > reg = devm_ioremap ( & pdev - > dev , res - > start ,
resource_size ( res ) ) ;
if ( ! dev - > reg )
return - ENOMEM ;
2014-03-15 22:17:57 +04:00
/* Each supported compatible has some RSTOUT register quirk */
if ( of_device_is_compatible ( node , " marvell,orion-wdt " ) ) {
dev - > rstout = orion_wdt_ioremap_rstout ( pdev , res - > start &
INTERNAL_REGS_MASK ) ;
if ( ! dev - > rstout )
return - ENODEV ;
} else if ( of_device_is_compatible ( node , " marvell,armada-370-wdt " ) | |
of_device_is_compatible ( node , " marvell,armada-xp-wdt " ) ) {
/* Dedicated RSTOUT register, can be requested. */
watchdog: Convert to use devm_platform_ioremap_resource
Use devm_platform_ioremap_resource to reduce source code size,
improve readability, and reduce the likelyhood of bugs.
The conversion was done automatically with coccinelle using the
following semantic patch.
@r@
identifier res, pdev;
expression a;
expression index;
expression e;
@@
<+...
- res = platform_get_resource(pdev, IORESOURCE_MEM, index);
- a = devm_ioremap_resource(e, res);
+ a = devm_platform_ioremap_resource(pdev, index);
...+>
@depends on r@
identifier r.res;
@@
- struct resource *res;
... when != res
@@
identifier res, pdev;
expression index;
expression a;
@@
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, index);
- a = devm_ioremap_resource(&pdev->dev, res);
+ a = devm_platform_ioremap_resource(pdev, index);
Cc: Joel Stanley <joel@jms.id.au>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Baruch Siach <baruch@tkos.co.il>
Cc: Keguang Zhang <keguang.zhang@gmail.com>
Cc: Vladimir Zapolskiy <vz@mleia.com>
Cc: Kevin Hilman <khilman@baylibre.com>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Cc: Avi Fishman <avifishman70@gmail.com>
Cc: Nancy Yuen <yuenn@google.com>
Cc: Brendan Higgins <brendanhiggins@google.com>
Cc: Wan ZongShun <mcuos.com@gmail.com>
Cc: Michal Simek <michal.simek@xilinx.com>
Cc: Sylvain Lemieux <slemieux.tyco@gmail.com>
Cc: Kukjin Kim <kgene@kernel.org>
Cc: Barry Song <baohua@kernel.org>
Cc: Orson Zhai <orsonzhai@gmail.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Maxime Ripard <maxime.ripard@bootlin.com>
Cc: Chen-Yu Tsai <wens@csie.org>
Cc: Marc Gonzalez <marc.w.gonzalez@free.fr>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Tested-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>
Acked-by: Michal Simek <michal.simek@xilinx.com> (cadence/xilinx wdts)
Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Patrice Chotard <patrice.chotard@st.com>
Acked-by: Vladimir Zapolskiy <vz@mleia.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
2019-04-02 22:01:53 +03:00
dev - > rstout = devm_platform_ioremap_resource ( pdev , 1 ) ;
2014-03-15 22:17:57 +04:00
if ( IS_ERR ( dev - > rstout ) )
return PTR_ERR ( dev - > rstout ) ;
2014-03-15 22:18:01 +04:00
} else if ( of_device_is_compatible ( node , " marvell,armada-375-wdt " ) | |
of_device_is_compatible ( node , " marvell,armada-380-wdt " ) ) {
/* Dedicated RSTOUT register, can be requested. */
watchdog: Convert to use devm_platform_ioremap_resource
Use devm_platform_ioremap_resource to reduce source code size,
improve readability, and reduce the likelyhood of bugs.
The conversion was done automatically with coccinelle using the
following semantic patch.
@r@
identifier res, pdev;
expression a;
expression index;
expression e;
@@
<+...
- res = platform_get_resource(pdev, IORESOURCE_MEM, index);
- a = devm_ioremap_resource(e, res);
+ a = devm_platform_ioremap_resource(pdev, index);
...+>
@depends on r@
identifier r.res;
@@
- struct resource *res;
... when != res
@@
identifier res, pdev;
expression index;
expression a;
@@
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, index);
- a = devm_ioremap_resource(&pdev->dev, res);
+ a = devm_platform_ioremap_resource(pdev, index);
Cc: Joel Stanley <joel@jms.id.au>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Baruch Siach <baruch@tkos.co.il>
Cc: Keguang Zhang <keguang.zhang@gmail.com>
Cc: Vladimir Zapolskiy <vz@mleia.com>
Cc: Kevin Hilman <khilman@baylibre.com>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Cc: Avi Fishman <avifishman70@gmail.com>
Cc: Nancy Yuen <yuenn@google.com>
Cc: Brendan Higgins <brendanhiggins@google.com>
Cc: Wan ZongShun <mcuos.com@gmail.com>
Cc: Michal Simek <michal.simek@xilinx.com>
Cc: Sylvain Lemieux <slemieux.tyco@gmail.com>
Cc: Kukjin Kim <kgene@kernel.org>
Cc: Barry Song <baohua@kernel.org>
Cc: Orson Zhai <orsonzhai@gmail.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Maxime Ripard <maxime.ripard@bootlin.com>
Cc: Chen-Yu Tsai <wens@csie.org>
Cc: Marc Gonzalez <marc.w.gonzalez@free.fr>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Tested-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>
Acked-by: Michal Simek <michal.simek@xilinx.com> (cadence/xilinx wdts)
Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Patrice Chotard <patrice.chotard@st.com>
Acked-by: Vladimir Zapolskiy <vz@mleia.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
2019-04-02 22:01:53 +03:00
dev - > rstout = devm_platform_ioremap_resource ( pdev , 1 ) ;
2014-03-15 22:18:01 +04:00
if ( IS_ERR ( dev - > rstout ) )
return PTR_ERR ( dev - > rstout ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 2 ) ;
if ( ! res )
return - ENODEV ;
dev - > rstout_mask = devm_ioremap ( & pdev - > dev , res - > start ,
resource_size ( res ) ) ;
if ( ! dev - > rstout_mask )
return - ENOMEM ;
2014-03-15 22:17:57 +04:00
} else {
2014-03-15 22:17:56 +04:00
return - ENODEV ;
2014-03-15 22:17:57 +04:00
}
2014-03-15 22:17:56 +04:00
return 0 ;
}
2012-11-19 22:21:41 +04:00
static int orion_wdt_probe ( struct platform_device * pdev )
2008-06-26 12:47:45 +04:00
{
2014-02-11 03:00:27 +04:00
struct orion_watchdog * dev ;
2014-02-11 03:00:28 +04:00
const struct of_device_id * match ;
2014-02-11 03:00:27 +04:00
unsigned int wdt_max_duration ; /* (seconds) */
2014-02-11 03:00:24 +04:00
int ret , irq ;
2008-06-26 12:47:45 +04:00
2014-02-11 03:00:27 +04:00
dev = devm_kzalloc ( & pdev - > dev , sizeof ( struct orion_watchdog ) ,
GFP_KERNEL ) ;
if ( ! dev )
return - ENOMEM ;
2014-02-11 03:00:28 +04:00
match = of_match_device ( orion_wdt_of_match_table , & pdev - > dev ) ;
if ( ! match )
/* Default legacy match */
match = & orion_wdt_of_match_table [ 0 ] ;
2014-02-11 03:00:27 +04:00
dev - > wdt . info = & orion_wdt_info ;
dev - > wdt . ops = & orion_wdt_ops ;
dev - > wdt . min_timeout = 1 ;
2014-02-11 03:00:28 +04:00
dev - > data = match - > data ;
2009-02-25 01:59:22 +03:00
2014-03-15 22:17:56 +04:00
ret = orion_wdt_get_regs ( pdev , dev ) ;
if ( ret )
return ret ;
2012-03-26 07:14:29 +04:00
2014-02-11 03:00:29 +04:00
ret = dev - > data - > clock_init ( pdev , dev ) ;
2012-03-26 07:14:29 +04:00
if ( ret ) {
2014-02-11 03:00:29 +04:00
dev_err ( & pdev - > dev , " cannot initialize clock \n " ) ;
2009-02-25 01:59:22 +03:00
return ret ;
2012-03-26 07:14:29 +04:00
}
2009-02-25 01:59:22 +03:00
2014-02-11 03:00:27 +04:00
wdt_max_duration = WDT_MAX_CYCLE_COUNT / dev - > clk_rate ;
dev - > wdt . timeout = wdt_max_duration ;
dev - > wdt . max_timeout = wdt_max_duration ;
2015-08-20 11:35:01 +03:00
dev - > wdt . parent = & pdev - > dev ;
2014-02-11 03:00:27 +04:00
watchdog_init_timeout ( & dev - > wdt , heartbeat , & pdev - > dev ) ;
2012-03-26 07:14:29 +04:00
2014-02-11 03:00:27 +04:00
platform_set_drvdata ( pdev , & dev - > wdt ) ;
watchdog_set_drvdata ( & dev - > wdt , dev ) ;
2012-03-26 07:14:29 +04:00
2014-02-11 03:00:23 +04:00
/*
* Let ' s make sure the watchdog is fully stopped , unless it ' s
* explicitly enabled . This may be the case if the module was
2017-10-11 05:29:56 +03:00
* removed and re - inserted , or if the bootloader explicitly
2014-02-11 03:00:23 +04:00
* set a running watchdog before booting the kernel .
*/
2014-03-15 22:18:00 +04:00
if ( ! orion_wdt_enabled ( & dev - > wdt ) )
2014-02-11 03:00:27 +04:00
orion_wdt_stop ( & dev - > wdt ) ;
2018-06-07 16:54:37 +03:00
else
set_bit ( WDOG_HW_RUNNING , & dev - > wdt . status ) ;
2014-02-11 03:00:23 +04:00
2014-02-11 03:00:24 +04:00
/* Request the IRQ only after the watchdog is disabled */
2019-11-29 17:51:35 +03:00
irq = platform_get_irq_optional ( pdev , 0 ) ;
2014-02-11 03:00:24 +04:00
if ( irq > 0 ) {
/*
* Not all supported platforms specify an interrupt for the
* watchdog , so let ' s make it optional .
*/
ret = devm_request_irq ( & pdev - > dev , irq , orion_wdt_irq , 0 ,
2014-02-11 03:00:27 +04:00
pdev - > name , dev ) ;
2014-02-11 03:00:24 +04:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to request IRQ \n " ) ;
goto disable_clk ;
}
}
2019-08-30 00:52:24 +03:00
/* Optional 2nd interrupt for pretimeout */
2019-11-29 17:51:35 +03:00
irq = platform_get_irq_optional ( pdev , 1 ) ;
2019-08-30 00:52:24 +03:00
if ( irq > 0 ) {
orion_wdt_info . options | = WDIOF_PRETIMEOUT ;
ret = devm_request_irq ( & pdev - > dev , irq , orion_wdt_pre_irq ,
0 , pdev - > name , dev ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to request IRQ \n " ) ;
goto disable_clk ;
}
}
2014-02-11 03:00:27 +04:00
watchdog_set_nowayout ( & dev - > wdt , nowayout ) ;
ret = watchdog_register_device ( & dev - > wdt ) ;
2014-02-11 03:00:20 +04:00
if ( ret )
goto disable_clk ;
2009-02-25 01:59:22 +03:00
2012-02-16 03:06:19 +04:00
pr_info ( " Initial timeout %d sec%s \n " ,
2014-02-11 03:00:27 +04:00
dev - > wdt . timeout , nowayout ? " , nowayout " : " " ) ;
2009-02-25 01:59:22 +03:00
return 0 ;
2014-02-11 03:00:20 +04:00
disable_clk :
2014-02-11 03:00:27 +04:00
clk_disable_unprepare ( dev - > clk ) ;
2014-02-11 03:00:31 +04:00
clk_put ( dev - > clk ) ;
2014-02-11 03:00:20 +04:00
return ret ;
2009-02-25 01:59:22 +03:00
}
2012-11-19 22:26:24 +04:00
static int orion_wdt_remove ( struct platform_device * pdev )
2009-02-25 01:59:22 +03:00
{
2014-02-11 03:00:27 +04:00
struct watchdog_device * wdt_dev = platform_get_drvdata ( pdev ) ;
struct orion_watchdog * dev = watchdog_get_drvdata ( wdt_dev ) ;
watchdog_unregister_device ( wdt_dev ) ;
clk_disable_unprepare ( dev - > clk ) ;
2014-02-11 03:00:31 +04:00
clk_put ( dev - > clk ) ;
2012-03-26 07:14:29 +04:00
return 0 ;
2008-06-26 12:47:45 +04:00
}
2009-06-01 21:56:02 +04:00
static void orion_wdt_shutdown ( struct platform_device * pdev )
2009-02-20 21:44:59 +03:00
{
2014-02-11 03:00:27 +04:00
struct watchdog_device * wdt_dev = platform_get_drvdata ( pdev ) ;
orion_wdt_stop ( wdt_dev ) ;
2009-02-20 21:44:59 +03:00
}
2009-06-01 21:56:02 +04:00
static struct platform_driver orion_wdt_driver = {
. probe = orion_wdt_probe ,
2012-11-19 22:21:12 +04:00
. remove = orion_wdt_remove ,
2009-06-01 21:56:02 +04:00
. shutdown = orion_wdt_shutdown ,
2009-02-25 01:59:22 +03:00
. driver = {
2009-06-01 21:56:02 +04:00
. name = " orion_wdt " ,
2013-09-30 08:42:51 +04:00
. of_match_table = orion_wdt_of_match_table ,
2009-02-25 01:59:22 +03:00
} ,
} ;
2011-11-29 09:56:27 +04:00
module_platform_driver ( orion_wdt_driver ) ;
2008-06-26 12:47:45 +04:00
MODULE_AUTHOR ( " Sylver Bruneau <sylver.bruneau@googlemail.com> " ) ;
2009-06-01 21:56:02 +04:00
MODULE_DESCRIPTION ( " Orion Processor Watchdog " ) ;
2008-06-26 12:47:45 +04:00
module_param ( heartbeat , int , 0 ) ;
2009-02-20 21:44:59 +03:00
MODULE_PARM_DESC ( heartbeat , " Initial watchdog heartbeat in seconds " ) ;
2008-06-26 12:47:45 +04:00
2012-03-05 19:51:11 +04:00
module_param ( nowayout , bool , 0 ) ;
2009-02-20 21:44:59 +03:00
MODULE_PARM_DESC ( nowayout , " Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
2008-06-26 12:47:45 +04:00
2017-03-29 18:34:24 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2013-01-04 18:06:28 +04:00
MODULE_ALIAS ( " platform:orion_wdt " ) ;