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 26 static unsigned int timeout = WATCHDOG_TIMEOUT; 27 module_param(timeout, uint, 0); 28 MODULE_PARM_DESC(timeout, 29 "Watchdog timeout in seconds. default=" 30 __MODULE_STRING(WATCHDOG_TIMEOUT) "."); 31 32 static bool nowayout = WATCHDOG_NOWAYOUT; 33 module_param(nowayout, bool, 0); 34 MODULE_PARM_DESC(nowayout, 35 "Watchdog cannot be stopped once started (default=" 36 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 37 38 static int db8500_wdt_start(struct watchdog_device *wdd) 39 { 40 return prcmu_enable_a9wdog(PRCMU_WDOG_ALL); 41 } 42 43 static int db8500_wdt_stop(struct watchdog_device *wdd) 44 { 45 return prcmu_disable_a9wdog(PRCMU_WDOG_ALL); 46 } 47 48 static int db8500_wdt_keepalive(struct watchdog_device *wdd) 49 { 50 return prcmu_kick_a9wdog(PRCMU_WDOG_ALL); 51 } 52 53 static 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 63 static 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 69 static 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 77 static 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 84 static 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 static int db8500_wdt_suspend(struct platform_device *pdev, 109 pm_message_t state) 110 { 111 if (watchdog_active(&db8500_wdt)) { 112 db8500_wdt_stop(&db8500_wdt); 113 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true); 114 115 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000); 116 db8500_wdt_start(&db8500_wdt); 117 } 118 return 0; 119 } 120 121 static int db8500_wdt_resume(struct platform_device *pdev) 122 { 123 if (watchdog_active(&db8500_wdt)) { 124 db8500_wdt_stop(&db8500_wdt); 125 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false); 126 127 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000); 128 db8500_wdt_start(&db8500_wdt); 129 } 130 return 0; 131 } 132 133 static struct platform_driver db8500_wdt_driver = { 134 .probe = db8500_wdt_probe, 135 .suspend = pm_ptr(db8500_wdt_suspend), 136 .resume = pm_ptr(db8500_wdt_resume), 137 .driver = { 138 .name = "db8500_wdt", 139 }, 140 }; 141 142 module_platform_driver(db8500_wdt_driver); 143 144 MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>"); 145 MODULE_DESCRIPTION("DB8500 Watchdog Driver"); 146 MODULE_LICENSE("GPL"); 147 MODULE_ALIAS("platform:db8500_wdt"); 148