1*502a0106SMark Brown /* 2*502a0106SMark Brown * Watchdog driver for the wm831x PMICs 3*502a0106SMark Brown * 4*502a0106SMark Brown * Copyright (C) 2009 Wolfson Microelectronics 5*502a0106SMark Brown * 6*502a0106SMark Brown * This program is free software; you can redistribute it and/or 7*502a0106SMark Brown * modify it under the terms of the GNU General Public License 8*502a0106SMark Brown * as published by the Free Software Foundation 9*502a0106SMark Brown */ 10*502a0106SMark Brown 11*502a0106SMark Brown #include <linux/module.h> 12*502a0106SMark Brown #include <linux/moduleparam.h> 13*502a0106SMark Brown #include <linux/types.h> 14*502a0106SMark Brown #include <linux/kernel.h> 15*502a0106SMark Brown #include <linux/fs.h> 16*502a0106SMark Brown #include <linux/miscdevice.h> 17*502a0106SMark Brown #include <linux/platform_device.h> 18*502a0106SMark Brown #include <linux/watchdog.h> 19*502a0106SMark Brown #include <linux/uaccess.h> 20*502a0106SMark Brown #include <linux/gpio.h> 21*502a0106SMark Brown 22*502a0106SMark Brown #include <linux/mfd/wm831x/core.h> 23*502a0106SMark Brown #include <linux/mfd/wm831x/pdata.h> 24*502a0106SMark Brown #include <linux/mfd/wm831x/watchdog.h> 25*502a0106SMark Brown 26*502a0106SMark Brown static int nowayout = WATCHDOG_NOWAYOUT; 27*502a0106SMark Brown module_param(nowayout, int, 0); 28*502a0106SMark Brown MODULE_PARM_DESC(nowayout, 29*502a0106SMark Brown "Watchdog cannot be stopped once started (default=" 30*502a0106SMark Brown __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 31*502a0106SMark Brown 32*502a0106SMark Brown static unsigned long wm831x_wdt_users; 33*502a0106SMark Brown static struct miscdevice wm831x_wdt_miscdev; 34*502a0106SMark Brown static int wm831x_wdt_expect_close; 35*502a0106SMark Brown static DEFINE_MUTEX(wdt_mutex); 36*502a0106SMark Brown static struct wm831x *wm831x; 37*502a0106SMark Brown static unsigned int update_gpio; 38*502a0106SMark Brown static unsigned int update_state; 39*502a0106SMark Brown 40*502a0106SMark Brown /* We can't use the sub-second values here but they're included 41*502a0106SMark Brown * for completeness. */ 42*502a0106SMark Brown static struct { 43*502a0106SMark Brown int time; /* Seconds */ 44*502a0106SMark Brown u16 val; /* WDOG_TO value */ 45*502a0106SMark Brown } wm831x_wdt_cfgs[] = { 46*502a0106SMark Brown { 1, 2 }, 47*502a0106SMark Brown { 2, 3 }, 48*502a0106SMark Brown { 4, 4 }, 49*502a0106SMark Brown { 8, 5 }, 50*502a0106SMark Brown { 16, 6 }, 51*502a0106SMark Brown { 32, 7 }, 52*502a0106SMark Brown { 33, 7 }, /* Actually 32.768s so include both, others round down */ 53*502a0106SMark Brown }; 54*502a0106SMark Brown 55*502a0106SMark Brown static int wm831x_wdt_set_timeout(struct wm831x *wm831x, u16 value) 56*502a0106SMark Brown { 57*502a0106SMark Brown int ret; 58*502a0106SMark Brown 59*502a0106SMark Brown mutex_lock(&wdt_mutex); 60*502a0106SMark Brown 61*502a0106SMark Brown ret = wm831x_reg_unlock(wm831x); 62*502a0106SMark Brown if (ret == 0) { 63*502a0106SMark Brown ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, 64*502a0106SMark Brown WM831X_WDOG_TO_MASK, value); 65*502a0106SMark Brown wm831x_reg_lock(wm831x); 66*502a0106SMark Brown } else { 67*502a0106SMark Brown dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 68*502a0106SMark Brown ret); 69*502a0106SMark Brown } 70*502a0106SMark Brown 71*502a0106SMark Brown mutex_unlock(&wdt_mutex); 72*502a0106SMark Brown 73*502a0106SMark Brown return ret; 74*502a0106SMark Brown } 75*502a0106SMark Brown 76*502a0106SMark Brown static int wm831x_wdt_start(struct wm831x *wm831x) 77*502a0106SMark Brown { 78*502a0106SMark Brown int ret; 79*502a0106SMark Brown 80*502a0106SMark Brown mutex_lock(&wdt_mutex); 81*502a0106SMark Brown 82*502a0106SMark Brown ret = wm831x_reg_unlock(wm831x); 83*502a0106SMark Brown if (ret == 0) { 84*502a0106SMark Brown ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, 85*502a0106SMark Brown WM831X_WDOG_ENA, WM831X_WDOG_ENA); 86*502a0106SMark Brown wm831x_reg_lock(wm831x); 87*502a0106SMark Brown } else { 88*502a0106SMark Brown dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 89*502a0106SMark Brown ret); 90*502a0106SMark Brown } 91*502a0106SMark Brown 92*502a0106SMark Brown mutex_unlock(&wdt_mutex); 93*502a0106SMark Brown 94*502a0106SMark Brown return ret; 95*502a0106SMark Brown } 96*502a0106SMark Brown 97*502a0106SMark Brown static int wm831x_wdt_stop(struct wm831x *wm831x) 98*502a0106SMark Brown { 99*502a0106SMark Brown int ret; 100*502a0106SMark Brown 101*502a0106SMark Brown mutex_lock(&wdt_mutex); 102*502a0106SMark Brown 103*502a0106SMark Brown ret = wm831x_reg_unlock(wm831x); 104*502a0106SMark Brown if (ret == 0) { 105*502a0106SMark Brown ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, 106*502a0106SMark Brown WM831X_WDOG_ENA, 0); 107*502a0106SMark Brown wm831x_reg_lock(wm831x); 108*502a0106SMark Brown } else { 109*502a0106SMark Brown dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 110*502a0106SMark Brown ret); 111*502a0106SMark Brown } 112*502a0106SMark Brown 113*502a0106SMark Brown mutex_unlock(&wdt_mutex); 114*502a0106SMark Brown 115*502a0106SMark Brown return ret; 116*502a0106SMark Brown } 117*502a0106SMark Brown 118*502a0106SMark Brown static int wm831x_wdt_kick(struct wm831x *wm831x) 119*502a0106SMark Brown { 120*502a0106SMark Brown int ret; 121*502a0106SMark Brown u16 reg; 122*502a0106SMark Brown 123*502a0106SMark Brown mutex_lock(&wdt_mutex); 124*502a0106SMark Brown 125*502a0106SMark Brown if (update_gpio) { 126*502a0106SMark Brown gpio_set_value_cansleep(update_gpio, update_state); 127*502a0106SMark Brown update_state = !update_state; 128*502a0106SMark Brown ret = 0; 129*502a0106SMark Brown goto out; 130*502a0106SMark Brown } 131*502a0106SMark Brown 132*502a0106SMark Brown 133*502a0106SMark Brown reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 134*502a0106SMark Brown 135*502a0106SMark Brown if (!(reg & WM831X_WDOG_RST_SRC)) { 136*502a0106SMark Brown dev_err(wm831x->dev, "Hardware watchdog update unsupported\n"); 137*502a0106SMark Brown ret = -EINVAL; 138*502a0106SMark Brown goto out; 139*502a0106SMark Brown } 140*502a0106SMark Brown 141*502a0106SMark Brown reg |= WM831X_WDOG_RESET; 142*502a0106SMark Brown 143*502a0106SMark Brown ret = wm831x_reg_unlock(wm831x); 144*502a0106SMark Brown if (ret == 0) { 145*502a0106SMark Brown ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); 146*502a0106SMark Brown wm831x_reg_lock(wm831x); 147*502a0106SMark Brown } else { 148*502a0106SMark Brown dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 149*502a0106SMark Brown ret); 150*502a0106SMark Brown } 151*502a0106SMark Brown 152*502a0106SMark Brown out: 153*502a0106SMark Brown mutex_unlock(&wdt_mutex); 154*502a0106SMark Brown 155*502a0106SMark Brown return ret; 156*502a0106SMark Brown } 157*502a0106SMark Brown 158*502a0106SMark Brown static int wm831x_wdt_open(struct inode *inode, struct file *file) 159*502a0106SMark Brown { 160*502a0106SMark Brown int ret; 161*502a0106SMark Brown 162*502a0106SMark Brown if (!wm831x) 163*502a0106SMark Brown return -ENODEV; 164*502a0106SMark Brown 165*502a0106SMark Brown if (test_and_set_bit(0, &wm831x_wdt_users)) 166*502a0106SMark Brown return -EBUSY; 167*502a0106SMark Brown 168*502a0106SMark Brown ret = wm831x_wdt_start(wm831x); 169*502a0106SMark Brown if (ret != 0) 170*502a0106SMark Brown return ret; 171*502a0106SMark Brown 172*502a0106SMark Brown return nonseekable_open(inode, file); 173*502a0106SMark Brown } 174*502a0106SMark Brown 175*502a0106SMark Brown static int wm831x_wdt_release(struct inode *inode, struct file *file) 176*502a0106SMark Brown { 177*502a0106SMark Brown if (wm831x_wdt_expect_close) 178*502a0106SMark Brown wm831x_wdt_stop(wm831x); 179*502a0106SMark Brown else { 180*502a0106SMark Brown dev_warn(wm831x->dev, "Watchdog device closed uncleanly\n"); 181*502a0106SMark Brown wm831x_wdt_kick(wm831x); 182*502a0106SMark Brown } 183*502a0106SMark Brown 184*502a0106SMark Brown clear_bit(0, &wm831x_wdt_users); 185*502a0106SMark Brown 186*502a0106SMark Brown return 0; 187*502a0106SMark Brown } 188*502a0106SMark Brown 189*502a0106SMark Brown static ssize_t wm831x_wdt_write(struct file *file, 190*502a0106SMark Brown const char __user *data, size_t count, 191*502a0106SMark Brown loff_t *ppos) 192*502a0106SMark Brown { 193*502a0106SMark Brown size_t i; 194*502a0106SMark Brown 195*502a0106SMark Brown if (count) { 196*502a0106SMark Brown wm831x_wdt_kick(wm831x); 197*502a0106SMark Brown 198*502a0106SMark Brown if (!nowayout) { 199*502a0106SMark Brown /* In case it was set long ago */ 200*502a0106SMark Brown wm831x_wdt_expect_close = 0; 201*502a0106SMark Brown 202*502a0106SMark Brown /* scan to see whether or not we got the magic 203*502a0106SMark Brown character */ 204*502a0106SMark Brown for (i = 0; i != count; i++) { 205*502a0106SMark Brown char c; 206*502a0106SMark Brown if (get_user(c, data + i)) 207*502a0106SMark Brown return -EFAULT; 208*502a0106SMark Brown if (c == 'V') 209*502a0106SMark Brown wm831x_wdt_expect_close = 42; 210*502a0106SMark Brown } 211*502a0106SMark Brown } 212*502a0106SMark Brown } 213*502a0106SMark Brown return count; 214*502a0106SMark Brown } 215*502a0106SMark Brown 216*502a0106SMark Brown static struct watchdog_info ident = { 217*502a0106SMark Brown .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 218*502a0106SMark Brown .identity = "WM831x Watchdog", 219*502a0106SMark Brown }; 220*502a0106SMark Brown 221*502a0106SMark Brown static long wm831x_wdt_ioctl(struct file *file, unsigned int cmd, 222*502a0106SMark Brown unsigned long arg) 223*502a0106SMark Brown { 224*502a0106SMark Brown int ret = -ENOTTY, time, i; 225*502a0106SMark Brown void __user *argp = (void __user *)arg; 226*502a0106SMark Brown int __user *p = argp; 227*502a0106SMark Brown u16 reg; 228*502a0106SMark Brown 229*502a0106SMark Brown switch (cmd) { 230*502a0106SMark Brown case WDIOC_GETSUPPORT: 231*502a0106SMark Brown ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; 232*502a0106SMark Brown break; 233*502a0106SMark Brown 234*502a0106SMark Brown case WDIOC_GETSTATUS: 235*502a0106SMark Brown case WDIOC_GETBOOTSTATUS: 236*502a0106SMark Brown ret = put_user(0, p); 237*502a0106SMark Brown break; 238*502a0106SMark Brown 239*502a0106SMark Brown case WDIOC_SETOPTIONS: 240*502a0106SMark Brown { 241*502a0106SMark Brown int options; 242*502a0106SMark Brown 243*502a0106SMark Brown if (get_user(options, p)) 244*502a0106SMark Brown return -EFAULT; 245*502a0106SMark Brown 246*502a0106SMark Brown ret = -EINVAL; 247*502a0106SMark Brown 248*502a0106SMark Brown /* Setting both simultaneously means at least one must fail */ 249*502a0106SMark Brown if (options == WDIOS_DISABLECARD) 250*502a0106SMark Brown ret = wm831x_wdt_start(wm831x); 251*502a0106SMark Brown 252*502a0106SMark Brown if (options == WDIOS_ENABLECARD) 253*502a0106SMark Brown ret = wm831x_wdt_stop(wm831x); 254*502a0106SMark Brown break; 255*502a0106SMark Brown } 256*502a0106SMark Brown 257*502a0106SMark Brown case WDIOC_KEEPALIVE: 258*502a0106SMark Brown ret = wm831x_wdt_kick(wm831x); 259*502a0106SMark Brown break; 260*502a0106SMark Brown 261*502a0106SMark Brown case WDIOC_SETTIMEOUT: 262*502a0106SMark Brown ret = get_user(time, p); 263*502a0106SMark Brown if (ret) 264*502a0106SMark Brown break; 265*502a0106SMark Brown 266*502a0106SMark Brown if (time == 0) { 267*502a0106SMark Brown if (nowayout) 268*502a0106SMark Brown ret = -EINVAL; 269*502a0106SMark Brown else 270*502a0106SMark Brown wm831x_wdt_stop(wm831x); 271*502a0106SMark Brown break; 272*502a0106SMark Brown } 273*502a0106SMark Brown 274*502a0106SMark Brown for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) 275*502a0106SMark Brown if (wm831x_wdt_cfgs[i].time == time) 276*502a0106SMark Brown break; 277*502a0106SMark Brown if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) 278*502a0106SMark Brown ret = -EINVAL; 279*502a0106SMark Brown else 280*502a0106SMark Brown ret = wm831x_wdt_set_timeout(wm831x, 281*502a0106SMark Brown wm831x_wdt_cfgs[i].val); 282*502a0106SMark Brown break; 283*502a0106SMark Brown 284*502a0106SMark Brown case WDIOC_GETTIMEOUT: 285*502a0106SMark Brown reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 286*502a0106SMark Brown reg &= WM831X_WDOG_TO_MASK; 287*502a0106SMark Brown for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) 288*502a0106SMark Brown if (wm831x_wdt_cfgs[i].val == reg) 289*502a0106SMark Brown break; 290*502a0106SMark Brown if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) { 291*502a0106SMark Brown dev_warn(wm831x->dev, 292*502a0106SMark Brown "Unknown watchdog configuration: %x\n", reg); 293*502a0106SMark Brown ret = -EINVAL; 294*502a0106SMark Brown } else 295*502a0106SMark Brown ret = put_user(wm831x_wdt_cfgs[i].time, p); 296*502a0106SMark Brown 297*502a0106SMark Brown } 298*502a0106SMark Brown 299*502a0106SMark Brown return ret; 300*502a0106SMark Brown } 301*502a0106SMark Brown 302*502a0106SMark Brown static const struct file_operations wm831x_wdt_fops = { 303*502a0106SMark Brown .owner = THIS_MODULE, 304*502a0106SMark Brown .llseek = no_llseek, 305*502a0106SMark Brown .write = wm831x_wdt_write, 306*502a0106SMark Brown .unlocked_ioctl = wm831x_wdt_ioctl, 307*502a0106SMark Brown .open = wm831x_wdt_open, 308*502a0106SMark Brown .release = wm831x_wdt_release, 309*502a0106SMark Brown }; 310*502a0106SMark Brown 311*502a0106SMark Brown static struct miscdevice wm831x_wdt_miscdev = { 312*502a0106SMark Brown .minor = WATCHDOG_MINOR, 313*502a0106SMark Brown .name = "watchdog", 314*502a0106SMark Brown .fops = &wm831x_wdt_fops, 315*502a0106SMark Brown }; 316*502a0106SMark Brown 317*502a0106SMark Brown static int __devinit wm831x_wdt_probe(struct platform_device *pdev) 318*502a0106SMark Brown { 319*502a0106SMark Brown struct wm831x_pdata *chip_pdata; 320*502a0106SMark Brown struct wm831x_watchdog_pdata *pdata; 321*502a0106SMark Brown int reg, ret; 322*502a0106SMark Brown 323*502a0106SMark Brown wm831x = dev_get_drvdata(pdev->dev.parent); 324*502a0106SMark Brown 325*502a0106SMark Brown ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 326*502a0106SMark Brown if (ret < 0) { 327*502a0106SMark Brown dev_err(wm831x->dev, "Failed to read watchdog status: %d\n", 328*502a0106SMark Brown ret); 329*502a0106SMark Brown goto err; 330*502a0106SMark Brown } 331*502a0106SMark Brown reg = ret; 332*502a0106SMark Brown 333*502a0106SMark Brown if (reg & WM831X_WDOG_DEBUG) 334*502a0106SMark Brown dev_warn(wm831x->dev, "Watchdog is paused\n"); 335*502a0106SMark Brown 336*502a0106SMark Brown /* Apply any configuration */ 337*502a0106SMark Brown if (pdev->dev.parent->platform_data) { 338*502a0106SMark Brown chip_pdata = pdev->dev.parent->platform_data; 339*502a0106SMark Brown pdata = chip_pdata->watchdog; 340*502a0106SMark Brown } else { 341*502a0106SMark Brown pdata = NULL; 342*502a0106SMark Brown } 343*502a0106SMark Brown 344*502a0106SMark Brown if (pdata) { 345*502a0106SMark Brown reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK | 346*502a0106SMark Brown WM831X_WDOG_RST_SRC); 347*502a0106SMark Brown 348*502a0106SMark Brown reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT; 349*502a0106SMark Brown reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT; 350*502a0106SMark Brown reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT; 351*502a0106SMark Brown 352*502a0106SMark Brown if (pdata->update_gpio) { 353*502a0106SMark Brown ret = gpio_request(pdata->update_gpio, 354*502a0106SMark Brown "Watchdog update"); 355*502a0106SMark Brown if (ret < 0) { 356*502a0106SMark Brown dev_err(wm831x->dev, 357*502a0106SMark Brown "Failed to request update GPIO: %d\n", 358*502a0106SMark Brown ret); 359*502a0106SMark Brown goto err; 360*502a0106SMark Brown } 361*502a0106SMark Brown 362*502a0106SMark Brown ret = gpio_direction_output(pdata->update_gpio, 0); 363*502a0106SMark Brown if (ret != 0) { 364*502a0106SMark Brown dev_err(wm831x->dev, 365*502a0106SMark Brown "gpio_direction_output returned: %d\n", 366*502a0106SMark Brown ret); 367*502a0106SMark Brown goto err_gpio; 368*502a0106SMark Brown } 369*502a0106SMark Brown 370*502a0106SMark Brown update_gpio = pdata->update_gpio; 371*502a0106SMark Brown 372*502a0106SMark Brown /* Make sure the watchdog takes hardware updates */ 373*502a0106SMark Brown reg |= WM831X_WDOG_RST_SRC; 374*502a0106SMark Brown } 375*502a0106SMark Brown 376*502a0106SMark Brown ret = wm831x_reg_unlock(wm831x); 377*502a0106SMark Brown if (ret == 0) { 378*502a0106SMark Brown ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); 379*502a0106SMark Brown wm831x_reg_lock(wm831x); 380*502a0106SMark Brown } else { 381*502a0106SMark Brown dev_err(wm831x->dev, 382*502a0106SMark Brown "Failed to unlock security key: %d\n", ret); 383*502a0106SMark Brown goto err_gpio; 384*502a0106SMark Brown } 385*502a0106SMark Brown } 386*502a0106SMark Brown 387*502a0106SMark Brown wm831x_wdt_miscdev.parent = &pdev->dev; 388*502a0106SMark Brown 389*502a0106SMark Brown ret = misc_register(&wm831x_wdt_miscdev); 390*502a0106SMark Brown if (ret != 0) { 391*502a0106SMark Brown dev_err(wm831x->dev, "Failed to register miscdev: %d\n", ret); 392*502a0106SMark Brown goto err_gpio; 393*502a0106SMark Brown } 394*502a0106SMark Brown 395*502a0106SMark Brown return 0; 396*502a0106SMark Brown 397*502a0106SMark Brown err_gpio: 398*502a0106SMark Brown if (update_gpio) { 399*502a0106SMark Brown gpio_free(update_gpio); 400*502a0106SMark Brown update_gpio = 0; 401*502a0106SMark Brown } 402*502a0106SMark Brown err: 403*502a0106SMark Brown return ret; 404*502a0106SMark Brown } 405*502a0106SMark Brown 406*502a0106SMark Brown static int __devexit wm831x_wdt_remove(struct platform_device *pdev) 407*502a0106SMark Brown { 408*502a0106SMark Brown if (update_gpio) { 409*502a0106SMark Brown gpio_free(update_gpio); 410*502a0106SMark Brown update_gpio = 0; 411*502a0106SMark Brown } 412*502a0106SMark Brown 413*502a0106SMark Brown misc_deregister(&wm831x_wdt_miscdev); 414*502a0106SMark Brown 415*502a0106SMark Brown return 0; 416*502a0106SMark Brown } 417*502a0106SMark Brown 418*502a0106SMark Brown static struct platform_driver wm831x_wdt_driver = { 419*502a0106SMark Brown .probe = wm831x_wdt_probe, 420*502a0106SMark Brown .remove = __devexit_p(wm831x_wdt_remove), 421*502a0106SMark Brown .driver = { 422*502a0106SMark Brown .name = "wm831x-watchdog", 423*502a0106SMark Brown }, 424*502a0106SMark Brown }; 425*502a0106SMark Brown 426*502a0106SMark Brown static int __init wm831x_wdt_init(void) 427*502a0106SMark Brown { 428*502a0106SMark Brown return platform_driver_register(&wm831x_wdt_driver); 429*502a0106SMark Brown } 430*502a0106SMark Brown module_init(wm831x_wdt_init); 431*502a0106SMark Brown 432*502a0106SMark Brown static void __exit wm831x_wdt_exit(void) 433*502a0106SMark Brown { 434*502a0106SMark Brown platform_driver_unregister(&wm831x_wdt_driver); 435*502a0106SMark Brown } 436*502a0106SMark Brown module_exit(wm831x_wdt_exit); 437*502a0106SMark Brown 438*502a0106SMark Brown MODULE_AUTHOR("Mark Brown"); 439*502a0106SMark Brown MODULE_DESCRIPTION("WM831x Watchdog"); 440*502a0106SMark Brown MODULE_LICENSE("GPL"); 441*502a0106SMark Brown MODULE_ALIAS("platform:wm831x-watchdog"); 442