10400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun/* 20400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * Copyright (c) 2009 Nuvoton technology corporation. 30400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 40400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * Wan ZongShun <mcuos.com@gmail.com> 50400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 60400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * This program is free software; you can redistribute it and/or modify 70400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * it under the terms of the GNU General Public License as published by 80400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * the Free Software Foundation;version 2 of the License. 90400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 100400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun */ 110400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 120400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/bitops.h> 130400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/errno.h> 140400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/fs.h> 150400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/io.h> 160400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/clk.h> 170400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/kernel.h> 180400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/miscdevice.h> 190400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/module.h> 200400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/moduleparam.h> 210400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/platform_device.h> 225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 230400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/interrupt.h> 240400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/types.h> 250400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/watchdog.h> 260400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#include <linux/uaccess.h> 270400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 280400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define REG_WTCR 0x1c 290400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WTCLK (0x01 << 10) 300400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WTE (0x01 << 7) /*wdt enable*/ 310400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WTIS (0x03 << 4) 320400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WTIF (0x01 << 3) 330400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WTRF (0x01 << 2) 340400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WTRE (0x01 << 1) 350400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WTR (0x01 << 0) 360400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun/* 370400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * The watchdog time interval can be calculated via following formula: 380400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * WTIS real time interval (formula) 390400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 0x00 ((2^ 14 ) * ((external crystal freq) / 256))seconds 400400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 0x01 ((2^ 16 ) * ((external crystal freq) / 256))seconds 410400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 0x02 ((2^ 18 ) * ((external crystal freq) / 256))seconds 420400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 0x03 ((2^ 20 ) * ((external crystal freq) / 256))seconds 430400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 440400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * The external crystal freq is 15Mhz in the nuc900 evaluation board. 450400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * So 0x00 = +-0.28 seconds, 0x01 = +-1.12 seconds, 0x02 = +-4.48 seconds, 460400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun * 0x03 = +- 16.92 seconds.. 470400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun */ 480400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WDT_HW_TIMEOUT 0x02 490400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WDT_TIMEOUT (HZ/2) 500400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun#define WDT_HEARTBEAT 15 510400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 520400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic int heartbeat = WDT_HEARTBEAT; 530400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunmodule_param(heartbeat, int, 0); 540400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunMODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. " 550400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")"); 560400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 5786a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT; 5886a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0); 590400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunMODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 600400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 610400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 620400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstruct nuc900_wdt { 630400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun struct clk *wdt_clock; 640400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun struct platform_device *pdev; 650400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun void __iomem *wdt_base; 660400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun char expect_close; 670400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun struct timer_list timer; 680400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spinlock_t wdt_lock; 690400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun unsigned long next_heartbeat; 700400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun}; 710400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 720400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic unsigned long nuc900wdt_busy; 73e352829a67c1a80c73dfad33ba9dca8ddf2ef0fdAxel Linstatic struct nuc900_wdt *nuc900_wdt; 740400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 750400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic inline void nuc900_wdt_keepalive(void) 760400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 770400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun unsigned int val; 780400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 790400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spin_lock(&nuc900_wdt->wdt_lock); 800400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 810400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val = __raw_readl(nuc900_wdt->wdt_base + REG_WTCR); 820400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val |= (WTR | WTIF); 830400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun __raw_writel(val, nuc900_wdt->wdt_base + REG_WTCR); 840400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 850400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spin_unlock(&nuc900_wdt->wdt_lock); 860400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 870400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 880400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic inline void nuc900_wdt_start(void) 890400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 900400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun unsigned int val; 910400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 920400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spin_lock(&nuc900_wdt->wdt_lock); 930400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 940400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val = __raw_readl(nuc900_wdt->wdt_base + REG_WTCR); 950400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val |= (WTRE | WTE | WTR | WTCLK | WTIF); 960400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val &= ~WTIS; 970400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val |= (WDT_HW_TIMEOUT << 0x04); 980400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun __raw_writel(val, nuc900_wdt->wdt_base + REG_WTCR); 990400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1000400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spin_unlock(&nuc900_wdt->wdt_lock); 1010400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1020400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt->next_heartbeat = jiffies + heartbeat * HZ; 1030400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun mod_timer(&nuc900_wdt->timer, jiffies + WDT_TIMEOUT); 1040400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 1050400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1060400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic inline void nuc900_wdt_stop(void) 1070400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 1080400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun unsigned int val; 1090400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1100400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun del_timer(&nuc900_wdt->timer); 1110400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1120400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spin_lock(&nuc900_wdt->wdt_lock); 1130400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1140400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val = __raw_readl(nuc900_wdt->wdt_base + REG_WTCR); 1150400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun val &= ~WTE; 1160400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun __raw_writel(val, nuc900_wdt->wdt_base + REG_WTCR); 1170400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1180400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spin_unlock(&nuc900_wdt->wdt_lock); 1190400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 1200400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1210400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic inline void nuc900_wdt_ping(void) 1220400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 1230400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt->next_heartbeat = jiffies + heartbeat * HZ; 1240400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 1250400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1260400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic int nuc900_wdt_open(struct inode *inode, struct file *file) 1270400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 1280400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1290400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (test_and_set_bit(0, &nuc900wdt_busy)) 1300400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return -EBUSY; 1310400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1320400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt_start(); 1330400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1340400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return nonseekable_open(inode, file); 1350400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 1360400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1370400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic int nuc900_wdt_close(struct inode *inode, struct file *file) 1380400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 1390400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (nuc900_wdt->expect_close == 42) 1400400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt_stop(); 1410400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun else { 1420400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun dev_crit(&nuc900_wdt->pdev->dev, 1430400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun "Unexpected close, not stopping watchdog!\n"); 1440400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt_ping(); 1450400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } 1460400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1470400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt->expect_close = 0; 1480400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun clear_bit(0, &nuc900wdt_busy); 1490400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return 0; 1500400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 1510400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1520400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic const struct watchdog_info nuc900_wdt_info = { 1530400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .identity = "nuc900 watchdog", 1540400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | 1550400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun WDIOF_MAGICCLOSE, 1560400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun}; 1570400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1580400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic long nuc900_wdt_ioctl(struct file *file, 1590400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun unsigned int cmd, unsigned long arg) 1600400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 1610400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun void __user *argp = (void __user *)arg; 1620400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun int __user *p = argp; 1630400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun int new_value; 1640400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1650400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun switch (cmd) { 1660400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun case WDIOC_GETSUPPORT: 1670400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return copy_to_user(argp, &nuc900_wdt_info, 1680400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun sizeof(nuc900_wdt_info)) ? -EFAULT : 0; 1690400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun case WDIOC_GETSTATUS: 1700400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun case WDIOC_GETBOOTSTATUS: 1710400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return put_user(0, p); 1720400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1730400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun case WDIOC_KEEPALIVE: 1740400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt_ping(); 1750400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return 0; 1760400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1770400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun case WDIOC_SETTIMEOUT: 1780400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (get_user(new_value, p)) 1790400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return -EFAULT; 1800400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1810400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun heartbeat = new_value; 1820400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt_ping(); 1830400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1840400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return put_user(new_value, p); 1850400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun case WDIOC_GETTIMEOUT: 1860400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return put_user(heartbeat, p); 1870400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun default: 1880400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return -ENOTTY; 1890400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } 1900400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 1910400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1920400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic ssize_t nuc900_wdt_write(struct file *file, const char __user *data, 1930400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun size_t len, loff_t *ppos) 1940400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 1950400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (!len) 1960400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return 0; 1970400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 1980400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun /* Scan for magic character */ 1990400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (!nowayout) { 2000400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun size_t i; 2010400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2020400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt->expect_close = 0; 2030400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2040400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun for (i = 0; i < len; i++) { 2050400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun char c; 2060400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (get_user(c, data + i)) 2070400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return -EFAULT; 2080400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (c == 'V') { 2090400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt->expect_close = 42; 2100400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun break; 2110400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } 2120400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } 2130400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } 2140400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2150400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt_ping(); 2160400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return len; 2170400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 2180400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2190400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic void nuc900_wdt_timer_ping(unsigned long data) 2200400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 2210400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (time_before(jiffies, nuc900_wdt->next_heartbeat)) { 2220400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt_keepalive(); 2230400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun mod_timer(&nuc900_wdt->timer, jiffies + WDT_TIMEOUT); 2240400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } else 2250400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun dev_warn(&nuc900_wdt->pdev->dev, "Will reset the machine !\n"); 2260400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 2270400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2280400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic const struct file_operations nuc900wdt_fops = { 2290400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .owner = THIS_MODULE, 2300400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .llseek = no_llseek, 2310400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .unlocked_ioctl = nuc900_wdt_ioctl, 2320400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .open = nuc900_wdt_open, 2330400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .release = nuc900_wdt_close, 2340400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .write = nuc900_wdt_write, 2350400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun}; 2360400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2370400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic struct miscdevice nuc900wdt_miscdev = { 2380400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .minor = WATCHDOG_MINOR, 2390400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .name = "watchdog", 2400400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .fops = &nuc900wdt_fops, 2410400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun}; 2420400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2432d991a164a61858012651e13c59521975504e260Bill Pembertonstatic int nuc900wdt_probe(struct platform_device *pdev) 2440400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 2453666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han struct resource *res; 2460400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun int ret = 0; 2470400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2483666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han nuc900_wdt = devm_kzalloc(&pdev->dev, sizeof(*nuc900_wdt), 2493666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han GFP_KERNEL); 2500400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (!nuc900_wdt) 2510400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return -ENOMEM; 2520400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2530400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun nuc900_wdt->pdev = pdev; 2540400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2550400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun spin_lock_init(&nuc900_wdt->wdt_lock); 2560400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2573666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2583666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); 2593666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han if (IS_ERR(nuc900_wdt->wdt_base)) 2603666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han return PTR_ERR(nuc900_wdt->wdt_base); 2610400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2623666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han nuc900_wdt->wdt_clock = devm_clk_get(&pdev->dev, NULL); 2630400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun if (IS_ERR(nuc900_wdt->wdt_clock)) { 2640400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun dev_err(&pdev->dev, "failed to find watchdog clock source\n"); 2653666eb028827c3a9df942cbc0a16388898c5a686Jingoo Han return PTR_ERR(nuc900_wdt->wdt_clock); 2660400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } 2670400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2680400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun clk_enable(nuc900_wdt->wdt_clock); 2690400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2700400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun setup_timer(&nuc900_wdt->timer, nuc900_wdt_timer_ping, 0); 2710400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2722865e770c9dddd40676eadf7c3dfe80aee7628e4Axel Lin ret = misc_register(&nuc900wdt_miscdev); 2732865e770c9dddd40676eadf7c3dfe80aee7628e4Axel Lin if (ret) { 2740400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun dev_err(&pdev->dev, "err register miscdev on minor=%d (%d)\n", 2750400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun WATCHDOG_MINOR, ret); 2760400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun goto err_clk; 2770400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun } 2780400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2790400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return 0; 2800400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2810400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunerr_clk: 2820400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun clk_disable(nuc900_wdt->wdt_clock); 2830400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return ret; 2840400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 2850400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2864b12b896c27c3b54592816606679f5b02f638930Bill Pembertonstatic int nuc900wdt_remove(struct platform_device *pdev) 2870400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun{ 2880400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun misc_deregister(&nuc900wdt_miscdev); 2890400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2900400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun clk_disable(nuc900_wdt->wdt_clock); 2910400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2920400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun return 0; 2930400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun} 2940400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 2950400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunstatic struct platform_driver nuc900wdt_driver = { 2960400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .probe = nuc900wdt_probe, 29782268714bdf06bc06135efb707a9de590ab2d294Bill Pemberton .remove = nuc900wdt_remove, 2980400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .driver = { 2990400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .name = "nuc900-wdt", 3000400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun .owner = THIS_MODULE, 3010400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun }, 3020400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun}; 3030400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 304b8ec61189f3b4cd9d1b2856342f5d7676151d01cAxel Linmodule_platform_driver(nuc900wdt_driver); 3050400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShun 3060400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunMODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); 3070400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunMODULE_DESCRIPTION("Watchdog driver for NUC900"); 3080400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunMODULE_LICENSE("GPL"); 3090400e3134b03336617138f9ebf2cd0f117ceef20Wan ZongShunMODULE_ALIAS("platform:nuc900-wdt"); 310