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

watchdog: bcm47xx_wdt.c: use platform device

Instead of accessing the function to set the watchdog timer directly,
register a platform driver the platform could register to use this
watchdog driver.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

authored by

Hauke Mehrtens and committed by
Wim Van Sebroeck
f82dedf8 5434a04d

+88 -79
+79 -79
drivers/watchdog/bcm47xx_wdt.c
··· 3 3 * 4 4 * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs> 5 5 * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr> 6 + * Copyright (C) 2012-2013 Hauke Mehrtens <hauke@hauke-m.de> 6 7 * 7 8 * This program is free software; you can redistribute it and/or 8 9 * modify it under the terms of the GNU General Public License ··· 13 12 14 13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 14 15 + #include <linux/bcm47xx_wdt.h> 16 16 #include <linux/bitops.h> 17 17 #include <linux/errno.h> 18 18 #include <linux/init.h> 19 19 #include <linux/kernel.h> 20 20 #include <linux/module.h> 21 21 #include <linux/moduleparam.h> 22 + #include <linux/platform_device.h> 22 23 #include <linux/reboot.h> 23 24 #include <linux/types.h> 24 25 #include <linux/watchdog.h> 25 26 #include <linux/timer.h> 26 27 #include <linux/jiffies.h> 27 - #include <linux/ssb/ssb_embedded.h> 28 - #include <asm/mach-bcm47xx/bcm47xx.h> 29 28 30 29 #define DRV_NAME "bcm47xx_wdt" 31 30 ··· 44 43 "Watchdog cannot be stopped once started (default=" 45 44 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 46 45 47 - static struct timer_list wdt_timer; 48 - static atomic_t ticks; 49 - 50 - static inline void bcm47xx_wdt_hw_start(void) 46 + static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd) 51 47 { 52 - /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */ 53 - switch (bcm47xx_bus_type) { 54 - #ifdef CONFIG_BCM47XX_SSB 55 - case BCM47XX_BUS_TYPE_SSB: 56 - ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff); 57 - break; 58 - #endif 59 - #ifdef CONFIG_BCM47XX_BCMA 60 - case BCM47XX_BUS_TYPE_BCMA: 61 - bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 62 - 0xfffffff); 63 - break; 64 - #endif 65 - } 48 + return container_of(wdd, struct bcm47xx_wdt, wdd); 66 49 } 67 50 68 - static inline int bcm47xx_wdt_hw_stop(void) 51 + static void bcm47xx_timer_tick(unsigned long data) 69 52 { 70 - switch (bcm47xx_bus_type) { 71 - #ifdef CONFIG_BCM47XX_SSB 72 - case BCM47XX_BUS_TYPE_SSB: 73 - return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0); 74 - #endif 75 - #ifdef CONFIG_BCM47XX_BCMA 76 - case BCM47XX_BUS_TYPE_BCMA: 77 - bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0); 78 - return 0; 79 - #endif 80 - } 81 - return -EINVAL; 82 - } 53 + struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data; 54 + u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms); 83 55 84 - static void bcm47xx_timer_tick(unsigned long unused) 85 - { 86 - if (!atomic_dec_and_test(&ticks)) { 87 - bcm47xx_wdt_hw_start(); 88 - mod_timer(&wdt_timer, jiffies + HZ); 56 + if (!atomic_dec_and_test(&wdt->soft_ticks)) { 57 + wdt->timer_set_ms(wdt, next_tick); 58 + mod_timer(&wdt->soft_timer, jiffies + HZ); 89 59 } else { 90 60 pr_crit("Watchdog will fire soon!!!\n"); 91 61 } ··· 64 92 65 93 static int bcm47xx_wdt_keepalive(struct watchdog_device *wdd) 66 94 { 67 - atomic_set(&ticks, wdt_time); 95 + struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd); 96 + 97 + atomic_set(&wdt->soft_ticks, wdd->timeout); 68 98 69 99 return 0; 70 100 } 71 101 72 102 static int bcm47xx_wdt_start(struct watchdog_device *wdd) 73 103 { 74 - bcm47xx_wdt_pet(); 75 - bcm47xx_timer_tick(0); 104 + struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd); 105 + 106 + bcm47xx_wdt_keepalive(wdd); 107 + bcm47xx_timer_tick((unsigned long)wdt); 76 108 77 109 return 0; 78 110 } 79 111 80 112 static int bcm47xx_wdt_stop(struct watchdog_device *wdd) 81 113 { 82 - del_timer_sync(&wdt_timer); 83 - bcm47xx_wdt_hw_stop(); 114 + struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd); 115 + 116 + del_timer_sync(&wdt->soft_timer); 117 + wdt->timer_set(wdt, 0); 84 118 85 119 return 0; 86 120 } ··· 94 116 static int bcm47xx_wdt_set_timeout(struct watchdog_device *wdd, 95 117 unsigned int new_time) 96 118 { 97 - if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) 119 + if (new_time < 1 || new_time > WDT_MAX_TIME) { 120 + pr_warn("timeout value must be 1<=x<=%d, using %d\n", 121 + WDT_MAX_TIME, new_time); 98 122 return -EINVAL; 123 + } 99 124 100 - wdt_time = new_time; 125 + wdd->timeout = new_time; 101 126 return 0; 102 127 } 103 128 ··· 114 133 static int bcm47xx_wdt_notify_sys(struct notifier_block *this, 115 134 unsigned long code, void *unused) 116 135 { 136 + struct bcm47xx_wdt *wdt; 137 + 138 + wdt = container_of(this, struct bcm47xx_wdt, notifier); 117 139 if (code == SYS_DOWN || code == SYS_HALT) 118 - bcm47xx_wdt_stop(); 140 + wdt->wdd.ops->stop(&wdt->wdd); 119 141 return NOTIFY_DONE; 120 142 } 121 143 ··· 130 146 .set_timeout = bcm47xx_wdt_set_timeout, 131 147 }; 132 148 133 - static struct watchdog_device bcm47xx_wdt_wdd = { 134 - .info = &bcm47xx_wdt_info, 135 - .ops = &bcm47xx_wdt_ops, 136 - }; 137 - 138 - static struct notifier_block bcm47xx_wdt_notifier = { 139 - .notifier_call = bcm47xx_wdt_notify_sys, 140 - }; 141 - 142 - static int __init bcm47xx_wdt_init(void) 149 + static int bcm47xx_wdt_probe(struct platform_device *pdev) 143 150 { 144 151 int ret; 152 + struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); 145 153 146 - if (bcm47xx_wdt_hw_stop() < 0) 147 - return -ENODEV; 154 + if (!wdt) 155 + return -ENXIO; 148 156 149 - setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L); 157 + setup_timer(&wdt->soft_timer, bcm47xx_timer_tick, 158 + (long unsigned int)wdt); 150 159 151 - if (bcm47xx_wdt_settimeout(wdt_time)) { 152 - bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME); 153 - pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n", 154 - (WDT_MAX_TIME + 1), wdt_time); 155 - } 156 - watchdog_set_nowayout(&bcm47xx_wdt_wdd, nowayout); 157 - 158 - ret = register_reboot_notifier(&bcm47xx_wdt_notifier); 160 + wdt->wdd.ops = &bcm47xx_wdt_ops; 161 + wdt->wdd.info = &bcm47xx_wdt_info; 162 + wdt->wdd.timeout = WDT_DEFAULT_TIME; 163 + ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); 159 164 if (ret) 160 - return ret; 165 + goto err_timer; 166 + watchdog_set_nowayout(&wdt->wdd, nowayout); 161 167 162 - ret = watchdog_register_device(&bcm47xx_wdt_wdd); 163 - if (ret) { 164 - unregister_reboot_notifier(&bcm47xx_wdt_notifier); 165 - return ret; 166 - } 168 + wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys; 169 + 170 + ret = register_reboot_notifier(&wdt->notifier); 171 + if (ret) 172 + goto err_timer; 173 + 174 + ret = watchdog_register_device(&wdt->wdd); 175 + if (ret) 176 + goto err_notifier; 167 177 168 178 pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n", 169 179 wdt_time, nowayout ? ", nowayout" : ""); 170 180 return 0; 181 + 182 + err_notifier: 183 + unregister_reboot_notifier(&wdt->notifier); 184 + err_timer: 185 + del_timer_sync(&wdt->soft_timer); 186 + 187 + return ret; 171 188 } 172 189 173 - static void __exit bcm47xx_wdt_exit(void) 190 + static int bcm47xx_wdt_remove(struct platform_device *pdev) 174 191 { 175 - watchdog_unregister_device(&bcm47xx_wdt_wdd); 192 + struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); 176 193 177 - unregister_reboot_notifier(&bcm47xx_wdt_notifier); 194 + if (!wdt) 195 + return -ENXIO; 196 + 197 + watchdog_unregister_device(&wdt->wdd); 198 + unregister_reboot_notifier(&wdt->notifier); 199 + 200 + return 0; 178 201 } 179 202 180 - module_init(bcm47xx_wdt_init); 181 - module_exit(bcm47xx_wdt_exit); 203 + static struct platform_driver bcm47xx_wdt_driver = { 204 + .driver = { 205 + .owner = THIS_MODULE, 206 + .name = "bcm47xx-wdt", 207 + }, 208 + .probe = bcm47xx_wdt_probe, 209 + .remove = bcm47xx_wdt_remove, 210 + }; 211 + 212 + module_platform_driver(bcm47xx_wdt_driver); 182 213 183 214 MODULE_AUTHOR("Aleksandar Radovanovic"); 215 + MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>"); 184 216 MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx"); 185 217 MODULE_LICENSE("GPL");
+9
include/linux/bcm47xx_wdt.h
··· 1 1 #ifndef LINUX_BCM47XX_WDT_H_ 2 2 #define LINUX_BCM47XX_WDT_H_ 3 3 4 + #include <linux/notifier.h> 5 + #include <linux/timer.h> 4 6 #include <linux/types.h> 7 + #include <linux/watchdog.h> 5 8 6 9 7 10 struct bcm47xx_wdt { ··· 13 10 u32 max_timer_ms; 14 11 15 12 void *driver_data; 13 + 14 + struct watchdog_device wdd; 15 + struct notifier_block notifier; 16 + 17 + struct timer_list soft_timer; 18 + atomic_t soft_ticks; 16 19 }; 17 20 18 21 static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt)