Version:  2.0.40 2.2.26 2.4.37 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6

Linux/drivers/watchdog/s3c2410_wdt.c

  1 /* linux/drivers/char/watchdog/s3c2410_wdt.c
  2  *
  3  * Copyright (c) 2004 Simtec Electronics
  4  *      Ben Dooks <ben@simtec.co.uk>
  5  *
  6  * S3C2410 Watchdog Timer Support
  7  *
  8  * Based on, softdog.c by Alan Cox,
  9  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
 10  *
 11  * This program is free software; you can redistribute it and/or modify
 12  * it under the terms of the GNU General Public License as published by
 13  * the Free Software Foundation; either version 2 of the License, or
 14  * (at your option) any later version.
 15  *
 16  * This program is distributed in the hope that it will be useful,
 17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 19  * GNU General Public License for more details.
 20  *
 21  * You should have received a copy of the GNU General Public License
 22  * along with this program; if not, write to the Free Software
 23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 24 */
 25 
 26 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 27 
 28 #include <linux/module.h>
 29 #include <linux/moduleparam.h>
 30 #include <linux/types.h>
 31 #include <linux/timer.h>
 32 #include <linux/watchdog.h>
 33 #include <linux/platform_device.h>
 34 #include <linux/interrupt.h>
 35 #include <linux/clk.h>
 36 #include <linux/uaccess.h>
 37 #include <linux/io.h>
 38 #include <linux/cpufreq.h>
 39 #include <linux/slab.h>
 40 #include <linux/err.h>
 41 #include <linux/of.h>
 42 #include <linux/mfd/syscon.h>
 43 #include <linux/regmap.h>
 44 #include <linux/delay.h>
 45 
 46 #define S3C2410_WTCON           0x00
 47 #define S3C2410_WTDAT           0x04
 48 #define S3C2410_WTCNT           0x08
 49 
 50 #define S3C2410_WTCNT_MAXCNT    0xffff
 51 
 52 #define S3C2410_WTCON_RSTEN     (1 << 0)
 53 #define S3C2410_WTCON_INTEN     (1 << 2)
 54 #define S3C2410_WTCON_ENABLE    (1 << 5)
 55 
 56 #define S3C2410_WTCON_DIV16     (0 << 3)
 57 #define S3C2410_WTCON_DIV32     (1 << 3)
 58 #define S3C2410_WTCON_DIV64     (2 << 3)
 59 #define S3C2410_WTCON_DIV128    (3 << 3)
 60 
 61 #define S3C2410_WTCON_MAXDIV    0x80
 62 
 63 #define S3C2410_WTCON_PRESCALE(x)       ((x) << 8)
 64 #define S3C2410_WTCON_PRESCALE_MASK     (0xff << 8)
 65 #define S3C2410_WTCON_PRESCALE_MAX      0xff
 66 
 67 #define CONFIG_S3C2410_WATCHDOG_ATBOOT          (0)
 68 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME    (15)
 69 
 70 #define EXYNOS5_RST_STAT_REG_OFFSET             0x0404
 71 #define EXYNOS5_WDT_DISABLE_REG_OFFSET          0x0408
 72 #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET       0x040c
 73 #define QUIRK_HAS_PMU_CONFIG                    (1 << 0)
 74 #define QUIRK_HAS_RST_STAT                      (1 << 1)
 75 
 76 /* These quirks require that we have a PMU register map */
 77 #define QUIRKS_HAVE_PMUREG                      (QUIRK_HAS_PMU_CONFIG | \
 78                                                  QUIRK_HAS_RST_STAT)
 79 
 80 static bool nowayout    = WATCHDOG_NOWAYOUT;
 81 static int tmr_margin;
 82 static int tmr_atboot   = CONFIG_S3C2410_WATCHDOG_ATBOOT;
 83 static int soft_noboot;
 84 static int debug;
 85 
 86 module_param(tmr_margin,  int, 0);
 87 module_param(tmr_atboot,  int, 0);
 88 module_param(nowayout,   bool, 0);
 89 module_param(soft_noboot, int, 0);
 90 module_param(debug,       int, 0);
 91 
 92 MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default="
 93                 __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
 94 MODULE_PARM_DESC(tmr_atboot,
 95                 "Watchdog is started at boot time if set to 1, default="
 96                         __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
 97 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 98                         __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 99 MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
100                         "0 to reboot (default 0)");
101 MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
102 
103 /**
104  * struct s3c2410_wdt_variant - Per-variant config data
105  *
106  * @disable_reg: Offset in pmureg for the register that disables the watchdog
107  * timer reset functionality.
108  * @mask_reset_reg: Offset in pmureg for the register that masks the watchdog
109  * timer reset functionality.
110  * @mask_bit: Bit number for the watchdog timer in the disable register and the
111  * mask reset register.
112  * @rst_stat_reg: Offset in pmureg for the register that has the reset status.
113  * @rst_stat_bit: Bit number in the rst_stat register indicating a watchdog
114  * reset.
115  * @quirks: A bitfield of quirks.
116  */
117 
118 struct s3c2410_wdt_variant {
119         int disable_reg;
120         int mask_reset_reg;
121         int mask_bit;
122         int rst_stat_reg;
123         int rst_stat_bit;
124         u32 quirks;
125 };
126 
127 struct s3c2410_wdt {
128         struct device           *dev;
129         struct clk              *clock;
130         void __iomem            *reg_base;
131         unsigned int            count;
132         spinlock_t              lock;
133         unsigned long           wtcon_save;
134         unsigned long           wtdat_save;
135         struct watchdog_device  wdt_device;
136         struct notifier_block   freq_transition;
137         struct s3c2410_wdt_variant *drv_data;
138         struct regmap *pmureg;
139 };
140 
141 static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
142         .quirks = 0
143 };
144 
145 #ifdef CONFIG_OF
146 static const struct s3c2410_wdt_variant drv_data_exynos5250  = {
147         .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
148         .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
149         .mask_bit = 20,
150         .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
151         .rst_stat_bit = 20,
152         .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
153 };
154 
155 static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
156         .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
157         .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
158         .mask_bit = 0,
159         .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
160         .rst_stat_bit