14a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* 24a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * drivers/char/watchdog/sp805-wdt.c 34a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * 44a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * Watchdog driver for ARM SP805 watchdog module 54a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * 64a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * Copyright (C) 2010 ST Microelectronics 74a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * Viresh Kumar<viresh.kumar@st.com> 84a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * 94a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * This file is licensed under the terms of the GNU General Public 104a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * License version 2 or later. This program is licensed "as is" without any 114a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * warranty of any kind, whether express or implied. 124a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR */ 134a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 144a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/device.h> 154a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/resource.h> 164a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/amba/bus.h> 174a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/bitops.h> 184a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/clk.h> 194a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/fs.h> 204a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/init.h> 214a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/io.h> 224a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/ioport.h> 234a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/kernel.h> 244a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/math64.h> 254a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/miscdevice.h> 264a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/module.h> 274a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/moduleparam.h> 2816ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar#include <linux/pm.h> 294a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/slab.h> 304a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/spinlock.h> 314a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/types.h> 324a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/uaccess.h> 334a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#include <linux/watchdog.h> 344a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 354a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* default timeout in seconds */ 364a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define DEFAULT_TIMEOUT 60 374a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 384a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define MODULE_NAME "sp805-wdt" 394a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 404a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* watchdog register offsets and masks */ 414a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define WDTLOAD 0x000 424a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define LOAD_MIN 0x00000001 434a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define LOAD_MAX 0xFFFFFFFF 444a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define WDTVALUE 0x004 454a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define WDTCONTROL 0x008 464a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR /* control register masks */ 474a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define INT_ENABLE (1 << 0) 484a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define RESET_ENABLE (1 << 1) 494a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define WDTINTCLR 0x00C 504a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define WDTRIS 0x010 514a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define WDTMIS 0x014 524a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define INT_MASK (1 << 0) 534a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR#define WDTLOCK 0xC00 544a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define UNLOCK 0x1ACCE551 554a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define LOCK 0x00000001 564a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 574a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/** 584a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * struct sp805_wdt: sp805 wdt device structure 59bfae14b679063d85f10579bbfd532db58b122e29Viresh Kumar * @lock: spin lock protecting dev structure and io access 60bfae14b679063d85f10579bbfd532db58b122e29Viresh Kumar * @base: base address of wdt 61bfae14b679063d85f10579bbfd532db58b122e29Viresh Kumar * @clk: clock structure of wdt 62bfae14b679063d85f10579bbfd532db58b122e29Viresh Kumar * @adev: amba device structure of wdt 63bfae14b679063d85f10579bbfd532db58b122e29Viresh Kumar * @status: current status of wdt 64bfae14b679063d85f10579bbfd532db58b122e29Viresh Kumar * @load_val: load value to be set for current timeout 65bfae14b679063d85f10579bbfd532db58b122e29Viresh Kumar * @timeout: current programmed timeout 664a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR */ 674a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstruct sp805_wdt { 684a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spinlock_t lock; 694a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR void __iomem *base; 704a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR struct clk *clk; 714a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR struct amba_device *adev; 724a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR unsigned long status; 734a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define WDT_BUSY 0 744a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR #define WDT_CAN_BE_CLOSED 1 754a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR unsigned int load_val; 764a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR unsigned int timeout; 774a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR}; 784a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 794a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* local variables */ 804a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic struct sp805_wdt *wdt; 8186a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT; 824a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 834a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* This routine finds load value that will reset system in required timout */ 844a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic void wdt_setload(unsigned int timeout) 854a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 864a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR u64 load, rate; 874a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 884a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR rate = clk_get_rate(wdt->clk); 894a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 904a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR /* 914a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * sp805 runs counter with given value twice, after the end of first 924a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * counter it gives an interrupt and then starts counter again. If 9325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * interrupt already occurred then it resets the system. This is why 944a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR * load is half of what should be required. 954a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR */ 964a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR load = div_u64(rate, 2) * timeout - 1; 974a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 984a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR load = (load > LOAD_MAX) ? LOAD_MAX : load; 994a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR load = (load < LOAD_MIN) ? LOAD_MIN : load; 1004a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1014a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_lock(&wdt->lock); 1024a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt->load_val = load; 1034a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR /* roundup timeout to closest positive integer value */ 1044a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate); 1054a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_unlock(&wdt->lock); 1064a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 1074a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1084a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* returns number of seconds left for reset to occur */ 1094a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic u32 wdt_timeleft(void) 1104a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 1114a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR u64 load, rate; 1124a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1134a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR rate = clk_get_rate(wdt->clk); 1144a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1154a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_lock(&wdt->lock); 116d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar load = readl_relaxed(wdt->base + WDTVALUE); 1174a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1184a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR /*If the interrupt is inactive then time left is WDTValue + WDTLoad. */ 119d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK)) 1204a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR load += wdt->load_val + 1; 1214a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_unlock(&wdt->lock); 1224a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1234a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return div_u64(load, rate); 1244a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 1254a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1264a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* enables watchdog timers reset */ 1274a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic void wdt_enable(void) 1284a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 1294a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_lock(&wdt->lock); 1304a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 131d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(UNLOCK, wdt->base + WDTLOCK); 132d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(wdt->load_val, wdt->base + WDTLOAD); 133d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(INT_MASK, wdt->base + WDTINTCLR); 134d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL); 135d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(LOCK, wdt->base + WDTLOCK); 1364a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 137081d83a3393f65adc94fc4240b9926be3054f9dcNick Bowler /* Flush posted writes. */ 138d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar readl_relaxed(wdt->base + WDTLOCK); 1394a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_unlock(&wdt->lock); 1404a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 1414a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1424a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR/* disables watchdog timers reset */ 1434a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic void wdt_disable(void) 1444a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 1454a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_lock(&wdt->lock); 1464a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 147d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(UNLOCK, wdt->base + WDTLOCK); 148d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(0, wdt->base + WDTCONTROL); 149d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar writel_relaxed(LOCK, wdt->base + WDTLOCK); 1504a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 151081d83a3393f65adc94fc4240b9926be3054f9dcNick Bowler /* Flush posted writes. */ 152d2e8919bcfb63b662945d0e5cb9338f0f2229d10Viresh Kumar readl_relaxed(wdt->base + WDTLOCK); 1534a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_unlock(&wdt->lock); 1544a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 1554a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1564a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic ssize_t sp805_wdt_write(struct file *file, const char *data, 1574a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR size_t len, loff_t *ppos) 1584a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 1594a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (len) { 1604a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (!nowayout) { 1614a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR size_t i; 1624a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1634a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clear_bit(WDT_CAN_BE_CLOSED, &wdt->status); 1644a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1654a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR for (i = 0; i != len; i++) { 1664a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR char c; 1674a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1684a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (get_user(c, data + i)) 1694a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return -EFAULT; 1704a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR /* Check for Magic Close character */ 1714a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (c == 'V') { 1724a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR set_bit(WDT_CAN_BE_CLOSED, 1734a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR &wdt->status); 1744a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR break; 1754a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 1764a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 1774a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 1784a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt_enable(); 1794a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 1804a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return len; 1814a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 1824a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1834a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic const struct watchdog_info ident = { 1844a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 1854a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .identity = MODULE_NAME, 1864a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR}; 1874a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1884a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic long sp805_wdt_ioctl(struct file *file, unsigned int cmd, 1894a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR unsigned long arg) 1904a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 1914a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR int ret = -ENOTTY; 1924a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR unsigned int timeout; 1934a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 1944a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR switch (cmd) { 1954a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR case WDIOC_GETSUPPORT: 1964a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = copy_to_user((struct watchdog_info *)arg, &ident, 1974a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR sizeof(ident)) ? -EFAULT : 0; 1984a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR break; 1994a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2004a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR case WDIOC_GETSTATUS: 2014a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = put_user(0, (int *)arg); 2024a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR break; 2034a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2044a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR case WDIOC_KEEPALIVE: 2054a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt_enable(); 2064a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = 0; 2074a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR break; 2084a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2094a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR case WDIOC_SETTIMEOUT: 2104a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = get_user(timeout, (unsigned int *)arg); 2114a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (ret) 2124a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR break; 2134a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2144a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt_setload(timeout); 2154a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2164a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt_enable(); 2174a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR /* Fall through */ 2184a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2194a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR case WDIOC_GETTIMEOUT: 2204a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = put_user(wdt->timeout, (unsigned int *)arg); 2214a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR break; 2224a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR case WDIOC_GETTIMELEFT: 2234a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = put_user(wdt_timeleft(), (unsigned int *)arg); 2244a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR break; 2254a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 2264a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return ret; 2274a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 2284a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2294a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic int sp805_wdt_open(struct inode *inode, struct file *file) 2304a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 2314a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR int ret = 0; 2324a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2334a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (test_and_set_bit(WDT_BUSY, &wdt->status)) 2344a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return -EBUSY; 2354a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2364a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = clk_enable(wdt->clk); 2374a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (ret) { 2384a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_err(&wdt->adev->dev, "clock enable fail"); 2394a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR goto err; 2404a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 2414a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2424a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt_enable(); 2434a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2444a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR /* can not be closed, once enabled */ 2454a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clear_bit(WDT_CAN_BE_CLOSED, &wdt->status); 2464a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return nonseekable_open(inode, file); 2474a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2484a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARerr: 2494a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clear_bit(WDT_BUSY, &wdt->status); 2504a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return ret; 2514a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 2524a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2534a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic int sp805_wdt_release(struct inode *inode, struct file *file) 2544a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 2554a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (!test_bit(WDT_CAN_BE_CLOSED, &wdt->status)) { 2564a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clear_bit(WDT_BUSY, &wdt->status); 2574a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_warn(&wdt->adev->dev, "Device closed unexpectedly\n"); 2584a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return 0; 2594a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 2604a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2614a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt_disable(); 2624a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clk_disable(wdt->clk); 2634a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clear_bit(WDT_BUSY, &wdt->status); 2644a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2654a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return 0; 2664a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 2674a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2684a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic const struct file_operations sp805_wdt_fops = { 2694a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .owner = THIS_MODULE, 2704a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .llseek = no_llseek, 2714a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .write = sp805_wdt_write, 2724a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .unlocked_ioctl = sp805_wdt_ioctl, 2734a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .open = sp805_wdt_open, 2744a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .release = sp805_wdt_release, 2754a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR}; 2764a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2774a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic struct miscdevice sp805_wdt_miscdev = { 2784a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .minor = WATCHDOG_MINOR, 2794a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .name = "watchdog", 2804a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .fops = &sp805_wdt_fops, 2814a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR}; 2824a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 2834a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic int __devinit 284aa25afad2ca60d19457849ea75e9c31236f4e174Russell Kingsp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) 2854a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 2864a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR int ret = 0; 2874a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 288fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar if (!devm_request_mem_region(&adev->dev, adev->res.start, 289fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar resource_size(&adev->res), "sp805_wdt")) { 2904a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_warn(&adev->dev, "Failed to get memory region resource\n"); 2914a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = -ENOENT; 2924a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR goto err; 2934a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 2944a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 295fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL); 2964a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (!wdt) { 2974a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_warn(&adev->dev, "Kzalloc failed\n"); 2984a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = -ENOMEM; 299fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar goto err; 300fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar } 301fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar 302fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar wdt->base = devm_ioremap(&adev->dev, adev->res.start, 303fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar resource_size(&adev->res)); 304fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar if (!wdt->base) { 305fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar ret = -ENOMEM; 306fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar dev_warn(&adev->dev, "ioremap fail\n"); 307fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar goto err; 3084a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 3094a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3104a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt->clk = clk_get(&adev->dev, NULL); 3114a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (IS_ERR(wdt->clk)) { 3124a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_warn(&adev->dev, "Clock not found\n"); 3134a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = PTR_ERR(wdt->clk); 314fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0fViresh Kumar goto err; 3154a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 3164a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3174a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt->adev = adev; 3184a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR spin_lock_init(&wdt->lock); 3194a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR wdt_setload(DEFAULT_TIMEOUT); 3204a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3214a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR ret = misc_register(&sp805_wdt_miscdev); 3224a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR if (ret < 0) { 3234a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_warn(&adev->dev, "cannot register misc device\n"); 3244a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR goto err_misc_register; 3254a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR } 3264a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3274a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_info(&adev->dev, "registration successful\n"); 3284a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return 0; 3294a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3304a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARerr_misc_register: 3314a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clk_put(wdt->clk); 3324a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARerr: 3334a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR dev_err(&adev->dev, "Probe Failed!!!\n"); 3344a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return ret; 3354a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 3364a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3374a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic int __devexit sp805_wdt_remove(struct amba_device *adev) 3384a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR{ 3394a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR misc_deregister(&sp805_wdt_miscdev); 3404a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR clk_put(wdt->clk); 3414a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3424a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR return 0; 3434a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR} 3444a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 34516ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar#ifdef CONFIG_PM 34616ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumarstatic int sp805_wdt_suspend(struct device *dev) 34716ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar{ 34816ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar if (test_bit(WDT_BUSY, &wdt->status)) { 34916ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar wdt_disable(); 35016ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar clk_disable(wdt->clk); 35116ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar } 35216ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar 35316ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar return 0; 35416ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar} 35516ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar 35616ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumarstatic int sp805_wdt_resume(struct device *dev) 35716ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar{ 35816ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar int ret = 0; 35916ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar 36016ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar if (test_bit(WDT_BUSY, &wdt->status)) { 36116ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar ret = clk_enable(wdt->clk); 36216ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar if (ret) { 36316ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar dev_err(dev, "clock enable fail"); 36416ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar return ret; 36516ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar } 36616ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar wdt_enable(); 36716ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar } 36816ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar 36916ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar return ret; 37016ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar} 37116ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar#endif /* CONFIG_PM */ 37216ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar 37316ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumarstatic SIMPLE_DEV_PM_OPS(sp805_wdt_dev_pm_ops, sp805_wdt_suspend, 37416ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar sp805_wdt_resume); 37516ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar 376bb558dac6776386a4d6994540a009231dcf53ee1Nick Bowlerstatic struct amba_id sp805_wdt_ids[] = { 3774a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR { 3784a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .id = 0x00141805, 3794a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .mask = 0x00ffffff, 3804a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR }, 3814a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR { 0, 0 }, 3824a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR}; 3834a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 38417885b05b31c0d310f859982d2a56f167274547eDave MartinMODULE_DEVICE_TABLE(amba, sp805_wdt_ids); 38517885b05b31c0d310f859982d2a56f167274547eDave Martin 3864a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARstatic struct amba_driver sp805_wdt_driver = { 3874a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .drv = { 3884a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .name = MODULE_NAME, 38916ac4abe0d0ea0a8d42d6a2a7de2a4a00bbf5b40Viresh Kumar .pm = &sp805_wdt_dev_pm_ops, 3904a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR }, 3914a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .id_table = sp805_wdt_ids, 3924a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .probe = sp805_wdt_probe, 3934a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR .remove = __devexit_p(sp805_wdt_remove), 3944a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR}; 3954a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 3969e5ed094c89e55fbf11d2e81d60be98eb12346c0viresh kumarmodule_amba_driver(sp805_wdt_driver); 3974a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 39886a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0); 3994a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARMODULE_PARM_DESC(nowayout, 4004a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR "Set to 1 to keep watchdog running after device release"); 4014a370278e1041d4c62719bcd773e9c620e775901Viresh KUMAR 4024a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARMODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); 4034a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARMODULE_DESCRIPTION("ARM SP805 Watchdog Driver"); 4044a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARMODULE_LICENSE("GPL"); 4054a370278e1041d4c62719bcd773e9c620e775901Viresh KUMARMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 406