aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorDoug Anderson <dianders@chromium.org>2013-12-06 16:08:07 -0500
committerWim Van Sebroeck <wim@iguana.be>2014-01-28 15:24:33 -0500
commitcffc9a60ebac3b560a370553abd885fa43d8b286 (patch)
tree6f71e033b302db3941612e5567e4f66718c0a01b /drivers/watchdog
parent4f1f653a68d67ca5732fdd7ee4deb290a3ea5149 (diff)
watchdog: s3c2410_wdt: Report when the watchdog reset the system
A good watchdog driver is supposed to report when it was responsible for resetting the system. Implement this for the s3c2410, at least on exynos5250 and exynos5420 where we already have a pointer to the PMU registers to read the information. Note that exynos4 SoCs also provide the reset status, but providing that is left as an exercise for future changes and is not plumbed up in this patch series. Also note the exynos4 SoCs don't appear to need any PMU config, which is why this patch separates the concepts of having PMU Registers vs. needing PMU Config. Signed-off-by: Doug Anderson <dianders@chromium.org> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/s3c2410_wdt.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 64f5470a6a0e..aec946df6ed9 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -62,9 +62,15 @@
62#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) 62#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
63#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) 63#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
64 64
65#define EXYNOS5_RST_STAT_REG_OFFSET 0x0404
65#define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 66#define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408
66#define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c 67#define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c
67#define QUIRK_HAS_PMU_CONFIG (1 << 0) 68#define QUIRK_HAS_PMU_CONFIG (1 << 0)
69#define QUIRK_HAS_RST_STAT (1 << 1)
70
71/* These quirks require that we have a PMU register map */
72#define QUIRKS_HAVE_PMUREG (QUIRK_HAS_PMU_CONFIG | \
73 QUIRK_HAS_RST_STAT)
68 74
69static bool nowayout = WATCHDOG_NOWAYOUT; 75static bool nowayout = WATCHDOG_NOWAYOUT;
70static int tmr_margin; 76static int tmr_margin;
@@ -98,6 +104,9 @@ MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
98 * timer reset functionality. 104 * timer reset functionality.
99 * @mask_bit: Bit number for the watchdog timer in the disable register and the 105 * @mask_bit: Bit number for the watchdog timer in the disable register and the
100 * mask reset register. 106 * mask reset register.
107 * @rst_stat_reg: Offset in pmureg for the register that has the reset status.
108 * @rst_stat_bit: Bit number in the rst_stat register indicating a watchdog
109 * reset.
101 * @quirks: A bitfield of quirks. 110 * @quirks: A bitfield of quirks.
102 */ 111 */
103 112
@@ -105,6 +114,8 @@ struct s3c2410_wdt_variant {
105 int disable_reg; 114 int disable_reg;
106 int mask_reset_reg; 115 int mask_reset_reg;
107 int mask_bit; 116 int mask_bit;
117 int rst_stat_reg;
118 int rst_stat_bit;
108 u32 quirks; 119 u32 quirks;
109}; 120};
110 121
@@ -131,14 +142,18 @@ static const struct s3c2410_wdt_variant drv_data_exynos5250 = {
131 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, 142 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
132 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, 143 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
133 .mask_bit = 20, 144 .mask_bit = 20,
134 .quirks = QUIRK_HAS_PMU_CONFIG 145 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
146 .rst_stat_bit = 20,
147 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
135}; 148};
136 149
137static const struct s3c2410_wdt_variant drv_data_exynos5420 = { 150static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
138 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, 151 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
139 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, 152 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
140 .mask_bit = 0, 153 .mask_bit = 0,
141 .quirks = QUIRK_HAS_PMU_CONFIG 154 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
155 .rst_stat_bit = 9,
156 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
142}; 157};
143 158
144static const struct of_device_id s3c2410_wdt_match[] = { 159static const struct of_device_id s3c2410_wdt_match[] = {
@@ -424,6 +439,23 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
424} 439}
425#endif 440#endif
426 441
442static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
443{
444 unsigned int rst_stat;
445 int ret;
446
447 if (!(wdt->drv_data->quirks & QUIRK_HAS_RST_STAT))
448 return 0;
449
450 ret = regmap_read(wdt->pmureg, wdt->drv_data->rst_stat_reg, &rst_stat);
451 if (ret)
452 dev_warn(wdt->dev, "Couldn't get RST_STAT register\n");
453 else if (rst_stat & BIT(wdt->drv_data->rst_stat_bit))
454 return WDIOF_CARDRESET;
455
456 return 0;
457}
458
427/* s3c2410_get_wdt_driver_data */ 459/* s3c2410_get_wdt_driver_data */
428static inline struct s3c2410_wdt_variant * 460static inline struct s3c2410_wdt_variant *
429get_wdt_drv_data(struct platform_device *pdev) 461get_wdt_drv_data(struct platform_device *pdev)
@@ -461,7 +493,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
461 wdt->wdt_device = s3c2410_wdd; 493 wdt->wdt_device = s3c2410_wdd;
462 494
463 wdt->drv_data = get_wdt_drv_data(pdev); 495 wdt->drv_data = get_wdt_drv_data(pdev);
464 if (wdt->drv_data->quirks & QUIRK_HAS_PMU_CONFIG) { 496 if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
465 wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, 497 wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
466 "samsung,syscon-phandle"); 498 "samsung,syscon-phandle");
467 if (IS_ERR(wdt->pmureg)) { 499 if (IS_ERR(wdt->pmureg)) {
@@ -532,6 +564,8 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
532 564
533 watchdog_set_nowayout(&wdt->wdt_device, nowayout); 565 watchdog_set_nowayout(&wdt->wdt_device, nowayout);
534 566
567 wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt);
568
535 ret = watchdog_register_device(&wdt->wdt_device); 569 ret = watchdog_register_device(&wdt->wdt_device);
536 if (ret) { 570 if (ret) {
537 dev_err(dev, "cannot register watchdog (%d)\n", ret); 571 dev_err(dev, "cannot register watchdog (%d)\n", ret);