Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: introduce retu_wdt driver

Introduce Retu watchdog driver.

Cc: linux-watchdog@vger.kernel.org
Acked-by: Felipe Balbi <balbi@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

authored by

Aaro Koskinen and committed by
Wim Van Sebroeck
3d3a6d18 d1ec74ab

+191
+12
drivers/watchdog/Kconfig
··· 377 377 To compile this driver as a module, choose M here: the 378 378 module will be called ux500_wdt. 379 379 380 + config RETU_WATCHDOG 381 + tristate "Retu watchdog" 382 + depends on MFD_RETU 383 + select WATCHDOG_CORE 384 + help 385 + Retu watchdog driver for Nokia Internet Tablets (770, N800, 386 + N810). At least on N800 the watchdog cannot be disabled, so 387 + this driver is essential and you should enable it. 388 + 389 + To compile this driver as a module, choose M here: the 390 + module will be called retu_wdt. 391 + 380 392 # AVR32 Architecture 381 393 382 394 config AT32AP700X_WDT
+1
drivers/watchdog/Makefile
··· 53 53 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o 54 54 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o 55 55 obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o 56 + obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o 56 57 57 58 # AVR32 Architecture 58 59 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
+178
drivers/watchdog/retu_wdt.c
··· 1 + /* 2 + * Retu watchdog driver 3 + * 4 + * Copyright (C) 2004, 2005 Nokia Corporation 5 + * 6 + * Based on code written by Amit Kucheria and Michael Buesch. 7 + * Rewritten by Aaro Koskinen. 8 + * 9 + * This file is subject to the terms and conditions of the GNU General 10 + * Public License. See the file "COPYING" in the main directory of this 11 + * archive for more details. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + */ 18 + 19 + #include <linux/init.h> 20 + #include <linux/slab.h> 21 + #include <linux/errno.h> 22 + #include <linux/device.h> 23 + #include <linux/kernel.h> 24 + #include <linux/module.h> 25 + #include <linux/mfd/retu.h> 26 + #include <linux/watchdog.h> 27 + #include <linux/platform_device.h> 28 + 29 + /* Watchdog timer values in seconds */ 30 + #define RETU_WDT_MAX_TIMER 63 31 + 32 + struct retu_wdt_dev { 33 + struct retu_dev *rdev; 34 + struct device *dev; 35 + struct delayed_work ping_work; 36 + }; 37 + 38 + /* 39 + * Since Retu watchdog cannot be disabled in hardware, we must kick it 40 + * with a timer until userspace watchdog software takes over. If 41 + * CONFIG_WATCHDOG_NOWAYOUT is set, we never start the feeding. 42 + */ 43 + static void retu_wdt_ping_enable(struct retu_wdt_dev *wdev) 44 + { 45 + retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER); 46 + schedule_delayed_work(&wdev->ping_work, 47 + round_jiffies_relative(RETU_WDT_MAX_TIMER * HZ / 2)); 48 + } 49 + 50 + static void retu_wdt_ping_disable(struct retu_wdt_dev *wdev) 51 + { 52 + retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER); 53 + cancel_delayed_work_sync(&wdev->ping_work); 54 + } 55 + 56 + static void retu_wdt_ping_work(struct work_struct *work) 57 + { 58 + struct retu_wdt_dev *wdev = container_of(to_delayed_work(work), 59 + struct retu_wdt_dev, ping_work); 60 + retu_wdt_ping_enable(wdev); 61 + } 62 + 63 + static int retu_wdt_start(struct watchdog_device *wdog) 64 + { 65 + struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog); 66 + 67 + retu_wdt_ping_disable(wdev); 68 + 69 + return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout); 70 + } 71 + 72 + static int retu_wdt_stop(struct watchdog_device *wdog) 73 + { 74 + struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog); 75 + 76 + retu_wdt_ping_enable(wdev); 77 + 78 + return 0; 79 + } 80 + 81 + static int retu_wdt_ping(struct watchdog_device *wdog) 82 + { 83 + struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog); 84 + 85 + return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout); 86 + } 87 + 88 + static int retu_wdt_set_timeout(struct watchdog_device *wdog, 89 + unsigned int timeout) 90 + { 91 + struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog); 92 + 93 + wdog->timeout = timeout; 94 + return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout); 95 + } 96 + 97 + static const struct watchdog_info retu_wdt_info = { 98 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 99 + .identity = "Retu watchdog", 100 + }; 101 + 102 + static const struct watchdog_ops retu_wdt_ops = { 103 + .owner = THIS_MODULE, 104 + .start = retu_wdt_start, 105 + .stop = retu_wdt_stop, 106 + .ping = retu_wdt_ping, 107 + .set_timeout = retu_wdt_set_timeout, 108 + }; 109 + 110 + static int retu_wdt_probe(struct platform_device *pdev) 111 + { 112 + struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent); 113 + bool nowayout = WATCHDOG_NOWAYOUT; 114 + struct watchdog_device *retu_wdt; 115 + struct retu_wdt_dev *wdev; 116 + int ret; 117 + 118 + retu_wdt = devm_kzalloc(&pdev->dev, sizeof(*retu_wdt), GFP_KERNEL); 119 + if (!retu_wdt) 120 + return -ENOMEM; 121 + 122 + wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL); 123 + if (!wdev) 124 + return -ENOMEM; 125 + 126 + retu_wdt->info = &retu_wdt_info; 127 + retu_wdt->ops = &retu_wdt_ops; 128 + retu_wdt->timeout = RETU_WDT_MAX_TIMER; 129 + retu_wdt->min_timeout = 0; 130 + retu_wdt->max_timeout = RETU_WDT_MAX_TIMER; 131 + 132 + watchdog_set_drvdata(retu_wdt, wdev); 133 + watchdog_set_nowayout(retu_wdt, nowayout); 134 + 135 + wdev->rdev = rdev; 136 + wdev->dev = &pdev->dev; 137 + 138 + INIT_DELAYED_WORK(&wdev->ping_work, retu_wdt_ping_work); 139 + 140 + ret = watchdog_register_device(retu_wdt); 141 + if (ret < 0) 142 + return ret; 143 + 144 + if (nowayout) 145 + retu_wdt_ping(retu_wdt); 146 + else 147 + retu_wdt_ping_enable(wdev); 148 + 149 + platform_set_drvdata(pdev, retu_wdt); 150 + 151 + return 0; 152 + } 153 + 154 + static int retu_wdt_remove(struct platform_device *pdev) 155 + { 156 + struct watchdog_device *wdog = platform_get_drvdata(pdev); 157 + struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog); 158 + 159 + watchdog_unregister_device(wdog); 160 + cancel_delayed_work_sync(&wdev->ping_work); 161 + 162 + return 0; 163 + } 164 + 165 + static struct platform_driver retu_wdt_driver = { 166 + .probe = retu_wdt_probe, 167 + .remove = retu_wdt_remove, 168 + .driver = { 169 + .name = "retu-wdt", 170 + }, 171 + }; 172 + module_platform_driver(retu_wdt_driver); 173 + 174 + MODULE_ALIAS("platform:retu-wdt"); 175 + MODULE_DESCRIPTION("Retu watchdog"); 176 + MODULE_AUTHOR("Amit Kucheria"); 177 + MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>"); 178 + MODULE_LICENSE("GPL");