db8500_wdt.c (3729B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) ST-Ericsson SA 2011-2013 4 * 5 * Author: Mathieu Poirier <mathieu.poirier@linaro.org> for ST-Ericsson 6 * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson 7 */ 8 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11#include <linux/module.h> 12#include <linux/kernel.h> 13#include <linux/moduleparam.h> 14#include <linux/err.h> 15#include <linux/uaccess.h> 16#include <linux/watchdog.h> 17#include <linux/platform_device.h> 18 19#include <linux/mfd/dbx500-prcmu.h> 20 21#define WATCHDOG_TIMEOUT 600 /* 10 minutes */ 22 23#define WATCHDOG_MIN 0 24#define WATCHDOG_MAX28 268435 /* 28 bit resolution in ms == 268435.455 s */ 25 26static unsigned int timeout = WATCHDOG_TIMEOUT; 27module_param(timeout, uint, 0); 28MODULE_PARM_DESC(timeout, 29 "Watchdog timeout in seconds. default=" 30 __MODULE_STRING(WATCHDOG_TIMEOUT) "."); 31 32static bool nowayout = WATCHDOG_NOWAYOUT; 33module_param(nowayout, bool, 0); 34MODULE_PARM_DESC(nowayout, 35 "Watchdog cannot be stopped once started (default=" 36 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 37 38static int db8500_wdt_start(struct watchdog_device *wdd) 39{ 40 return prcmu_enable_a9wdog(PRCMU_WDOG_ALL); 41} 42 43static int db8500_wdt_stop(struct watchdog_device *wdd) 44{ 45 return prcmu_disable_a9wdog(PRCMU_WDOG_ALL); 46} 47 48static int db8500_wdt_keepalive(struct watchdog_device *wdd) 49{ 50 return prcmu_kick_a9wdog(PRCMU_WDOG_ALL); 51} 52 53static int db8500_wdt_set_timeout(struct watchdog_device *wdd, 54 unsigned int timeout) 55{ 56 db8500_wdt_stop(wdd); 57 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000); 58 db8500_wdt_start(wdd); 59 60 return 0; 61} 62 63static const struct watchdog_info db8500_wdt_info = { 64 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 65 .identity = "DB8500 WDT", 66 .firmware_version = 1, 67}; 68 69static const struct watchdog_ops db8500_wdt_ops = { 70 .owner = THIS_MODULE, 71 .start = db8500_wdt_start, 72 .stop = db8500_wdt_stop, 73 .ping = db8500_wdt_keepalive, 74 .set_timeout = db8500_wdt_set_timeout, 75}; 76 77static struct watchdog_device db8500_wdt = { 78 .info = &db8500_wdt_info, 79 .ops = &db8500_wdt_ops, 80 .min_timeout = WATCHDOG_MIN, 81 .max_timeout = WATCHDOG_MAX28, 82}; 83 84static int db8500_wdt_probe(struct platform_device *pdev) 85{ 86 struct device *dev = &pdev->dev; 87 int ret; 88 89 timeout = 600; /* Default to 10 minutes */ 90 db8500_wdt.parent = dev; 91 watchdog_set_nowayout(&db8500_wdt, nowayout); 92 93 /* disable auto off on sleep */ 94 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false); 95 96 /* set HW initial value */ 97 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000); 98 99 ret = devm_watchdog_register_device(dev, &db8500_wdt); 100 if (ret) 101 return ret; 102 103 dev_info(dev, "initialized\n"); 104 105 return 0; 106} 107 108#ifdef CONFIG_PM 109static int db8500_wdt_suspend(struct platform_device *pdev, 110 pm_message_t state) 111{ 112 if (watchdog_active(&db8500_wdt)) { 113 db8500_wdt_stop(&db8500_wdt); 114 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true); 115 116 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000); 117 db8500_wdt_start(&db8500_wdt); 118 } 119 return 0; 120} 121 122static int db8500_wdt_resume(struct platform_device *pdev) 123{ 124 if (watchdog_active(&db8500_wdt)) { 125 db8500_wdt_stop(&db8500_wdt); 126 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false); 127 128 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000); 129 db8500_wdt_start(&db8500_wdt); 130 } 131 return 0; 132} 133#else 134#define db8500_wdt_suspend NULL 135#define db8500_wdt_resume NULL 136#endif 137 138static struct platform_driver db8500_wdt_driver = { 139 .probe = db8500_wdt_probe, 140 .suspend = db8500_wdt_suspend, 141 .resume = db8500_wdt_resume, 142 .driver = { 143 .name = "db8500_wdt", 144 }, 145}; 146 147module_platform_driver(db8500_wdt_driver); 148 149MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>"); 150MODULE_DESCRIPTION("DB8500 Watchdog Driver"); 151MODULE_LICENSE("GPL"); 152MODULE_ALIAS("platform:db8500_wdt");