Blame view
drivers/watchdog/davinci_wdt.c
6.65 KB
7d831bf59 [WATCHDOG] davinc... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* * drivers/char/watchdog/davinci_wdt.c * * Watchdog driver for DaVinci DM644x/DM646x processors * * Copyright (C) 2006 Texas Instruments. * * 2007 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/init.h> #include <linux/bitops.h> #include <linux/platform_device.h> #include <linux/spinlock.h> |
f78b0a8f2 [WATCHDOG 08/57] ... |
25 26 |
#include <linux/uaccess.h> #include <linux/io.h> |
371d3525e [WATCHDOG] davinc... |
27 |
#include <linux/device.h> |
9fd868f44 [WATCHDOG] davinc... |
28 |
#include <linux/clk.h> |
5a0e3ad6a include cleanup: ... |
29 |
#include <linux/slab.h> |
7d831bf59 [WATCHDOG] davinc... |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#define MODULE_NAME "DAVINCI-WDT: " #define DEFAULT_HEARTBEAT 60 #define MAX_HEARTBEAT 600 /* really the max margin is 264/27MHz*/ /* Timer register set definition */ #define PID12 (0x0) #define EMUMGT (0x4) #define TIM12 (0x10) #define TIM34 (0x14) #define PRD12 (0x18) #define PRD34 (0x1C) #define TCR (0x20) #define TGCR (0x24) #define WDTCR (0x28) /* TCR bit definitions */ #define ENAMODE12_DISABLED (0 << 6) #define ENAMODE12_ONESHOT (1 << 6) #define ENAMODE12_PERIODIC (2 << 6) /* TGCR bit definitions */ #define TIM12RS_UNRESET (1 << 0) #define TIM34RS_UNRESET (1 << 1) #define TIMMODE_64BIT_WDOG (2 << 2) /* WDTCR bit definitions */ #define WDEN (1 << 14) #define WDFLAG (1 << 15) #define WDKEY_SEQ0 (0xa5c6 << 16) #define WDKEY_SEQ1 (0xda7e << 16) static int heartbeat = DEFAULT_HEARTBEAT; |
c7dfd0cca [WATCHDOG] spin_l... |
64 |
static DEFINE_SPINLOCK(io_lock); |
7d831bf59 [WATCHDOG] davinc... |
65 66 67 68 69 70 71 72 |
static unsigned long wdt_status; #define WDT_IN_USE 0 #define WDT_OK_TO_CLOSE 1 #define WDT_REGION_INITED 2 #define WDT_DEVICE_INITED 3 static struct resource *wdt_mem; static void __iomem *wdt_base; |
9fd868f44 [WATCHDOG] davinc... |
73 |
struct clk *wdt_clk; |
7d831bf59 [WATCHDOG] davinc... |
74 75 76 77 78 79 |
static void wdt_service(void) { spin_lock(&io_lock); /* put watchdog in service state */ |
371d3525e [WATCHDOG] davinc... |
80 |
iowrite32(WDKEY_SEQ0, wdt_base + WDTCR); |
7d831bf59 [WATCHDOG] davinc... |
81 |
/* put watchdog in active state */ |
371d3525e [WATCHDOG] davinc... |
82 |
iowrite32(WDKEY_SEQ1, wdt_base + WDTCR); |
7d831bf59 [WATCHDOG] davinc... |
83 84 85 86 87 88 89 90 |
spin_unlock(&io_lock); } static void wdt_enable(void) { u32 tgcr; u32 timer_margin; |
9fd868f44 [WATCHDOG] davinc... |
91 92 93 |
unsigned long wdt_freq; wdt_freq = clk_get_rate(wdt_clk); |
7d831bf59 [WATCHDOG] davinc... |
94 95 96 97 |
spin_lock(&io_lock); /* disable, internal clock source */ |
371d3525e [WATCHDOG] davinc... |
98 |
iowrite32(0, wdt_base + TCR); |
7d831bf59 [WATCHDOG] davinc... |
99 |
/* reset timer, set mode to 64-bit watchdog, and unreset */ |
371d3525e [WATCHDOG] davinc... |
100 |
iowrite32(0, wdt_base + TGCR); |
7d831bf59 [WATCHDOG] davinc... |
101 |
tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET; |
371d3525e [WATCHDOG] davinc... |
102 |
iowrite32(tgcr, wdt_base + TGCR); |
7d831bf59 [WATCHDOG] davinc... |
103 |
/* clear counter regs */ |
371d3525e [WATCHDOG] davinc... |
104 105 |
iowrite32(0, wdt_base + TIM12); iowrite32(0, wdt_base + TIM34); |
7d831bf59 [WATCHDOG] davinc... |
106 |
/* set timeout period */ |
9fd868f44 [WATCHDOG] davinc... |
107 |
timer_margin = (((u64)heartbeat * wdt_freq) & 0xffffffff); |
371d3525e [WATCHDOG] davinc... |
108 |
iowrite32(timer_margin, wdt_base + PRD12); |
9fd868f44 [WATCHDOG] davinc... |
109 |
timer_margin = (((u64)heartbeat * wdt_freq) >> 32); |
371d3525e [WATCHDOG] davinc... |
110 |
iowrite32(timer_margin, wdt_base + PRD34); |
7d831bf59 [WATCHDOG] davinc... |
111 |
/* enable run continuously */ |
371d3525e [WATCHDOG] davinc... |
112 |
iowrite32(ENAMODE12_PERIODIC, wdt_base + TCR); |
7d831bf59 [WATCHDOG] davinc... |
113 114 115 116 117 |
/* Once the WDT is in pre-active state write to * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are * write protected (except for the WDKEY field) */ /* put watchdog in pre-active state */ |
371d3525e [WATCHDOG] davinc... |
118 |
iowrite32(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR); |
7d831bf59 [WATCHDOG] davinc... |
119 |
/* put watchdog in active state */ |
371d3525e [WATCHDOG] davinc... |
120 |
iowrite32(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR); |
7d831bf59 [WATCHDOG] davinc... |
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
spin_unlock(&io_lock); } static int davinci_wdt_open(struct inode *inode, struct file *file) { if (test_and_set_bit(WDT_IN_USE, &wdt_status)) return -EBUSY; wdt_enable(); return nonseekable_open(inode, file); } static ssize_t davinci_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) { |
7d831bf59 [WATCHDOG] davinc... |
139 140 141 142 143 |
if (len) wdt_service(); return len; } |
42747d712 [WATCHDOG] watchd... |
144 |
static const struct watchdog_info ident = { |
f1a08cc9a [WATCHDOG] davinc... |
145 |
.options = WDIOF_KEEPALIVEPING, |
7d831bf59 [WATCHDOG] davinc... |
146 147 |
.identity = "DaVinci Watchdog", }; |
f78b0a8f2 [WATCHDOG 08/57] ... |
148 149 |
static long davinci_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
7d831bf59 [WATCHDOG] davinc... |
150 151 152 153 154 155 156 157 158 159 |
{ int ret = -ENOTTY; switch (cmd) { case WDIOC_GETSUPPORT: ret = copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)) ? -EFAULT : 0; break; case WDIOC_GETSTATUS: |
f1a08cc9a [WATCHDOG] davinc... |
160 |
case WDIOC_GETBOOTSTATUS: |
7d831bf59 [WATCHDOG] davinc... |
161 162 |
ret = put_user(0, (int *)arg); break; |
7d831bf59 [WATCHDOG] davinc... |
163 164 165 166 |
case WDIOC_KEEPALIVE: wdt_service(); ret = 0; break; |
0c06090c9 [WATCHDOG] Coding... |
167 168 169 170 |
case WDIOC_GETTIMEOUT: ret = put_user(heartbeat, (int *)arg); break; |
7d831bf59 [WATCHDOG] davinc... |
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
} return ret; } static int davinci_wdt_release(struct inode *inode, struct file *file) { wdt_service(); clear_bit(WDT_IN_USE, &wdt_status); return 0; } static const struct file_operations davinci_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = davinci_wdt_write, |
f78b0a8f2 [WATCHDOG 08/57] ... |
187 |
.unlocked_ioctl = davinci_wdt_ioctl, |
7d831bf59 [WATCHDOG] davinc... |
188 189 190 191 192 193 194 195 196 |
.open = davinci_wdt_open, .release = davinci_wdt_release, }; static struct miscdevice davinci_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &davinci_wdt_fops, }; |
b6bf291f1 [WATCHDOG] move p... |
197 |
static int __devinit davinci_wdt_probe(struct platform_device *pdev) |
7d831bf59 [WATCHDOG] davinc... |
198 199 |
{ int ret = 0, size; |
371d3525e [WATCHDOG] davinc... |
200 |
struct device *dev = &pdev->dev; |
7d831bf59 [WATCHDOG] davinc... |
201 |
|
9fd868f44 [WATCHDOG] davinc... |
202 203 204 205 206 |
wdt_clk = clk_get(dev, NULL); if (WARN_ON(IS_ERR(wdt_clk))) return PTR_ERR(wdt_clk); clk_enable(wdt_clk); |
7d831bf59 [WATCHDOG] davinc... |
207 208 |
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) heartbeat = DEFAULT_HEARTBEAT; |
371d3525e [WATCHDOG] davinc... |
209 210 |
dev_info(dev, "heartbeat %d sec ", heartbeat); |
7d831bf59 [WATCHDOG] davinc... |
211 |
|
f712eacf0 watchdog: Convert... |
212 213 |
wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (wdt_mem == NULL) { |
371d3525e [WATCHDOG] davinc... |
214 215 |
dev_err(dev, "failed to get memory region resource "); |
7d831bf59 [WATCHDOG] davinc... |
216 217 |
return -ENOENT; } |
f712eacf0 watchdog: Convert... |
218 219 |
size = resource_size(wdt_mem); if (!request_mem_region(wdt_mem->start, size, pdev->name)) { |
371d3525e [WATCHDOG] davinc... |
220 221 |
dev_err(dev, "failed to get memory region "); |
7d831bf59 [WATCHDOG] davinc... |
222 223 |
return -ENOENT; } |
371d3525e [WATCHDOG] davinc... |
224 |
|
f712eacf0 watchdog: Convert... |
225 |
wdt_base = ioremap(wdt_mem->start, size); |
371d3525e [WATCHDOG] davinc... |
226 227 228 |
if (!wdt_base) { dev_err(dev, "failed to map memory region "); |
f712eacf0 watchdog: Convert... |
229 230 |
release_mem_region(wdt_mem->start, size); wdt_mem = NULL; |
371d3525e [WATCHDOG] davinc... |
231 232 |
return -ENOMEM; } |
7d831bf59 [WATCHDOG] davinc... |
233 234 235 |
ret = misc_register(&davinci_wdt_miscdev); if (ret < 0) { |
371d3525e [WATCHDOG] davinc... |
236 237 |
dev_err(dev, "cannot register misc device "); |
f712eacf0 watchdog: Convert... |
238 239 |
release_mem_region(wdt_mem->start, size); wdt_mem = NULL; |
7d831bf59 [WATCHDOG] davinc... |
240 241 242 |
} else { set_bit(WDT_DEVICE_INITED, &wdt_status); } |
371d3525e [WATCHDOG] davinc... |
243 |
iounmap(wdt_base); |
7d831bf59 [WATCHDOG] davinc... |
244 245 |
return ret; } |
b6bf291f1 [WATCHDOG] move p... |
246 |
static int __devexit davinci_wdt_remove(struct platform_device *pdev) |
7d831bf59 [WATCHDOG] davinc... |
247 248 249 |
{ misc_deregister(&davinci_wdt_miscdev); if (wdt_mem) { |
f712eacf0 watchdog: Convert... |
250 |
release_mem_region(wdt_mem->start, resource_size(wdt_mem)); |
7d831bf59 [WATCHDOG] davinc... |
251 252 |
wdt_mem = NULL; } |
9fd868f44 [WATCHDOG] davinc... |
253 254 255 |
clk_disable(wdt_clk); clk_put(wdt_clk); |
7d831bf59 [WATCHDOG] davinc... |
256 257 258 259 260 261 |
return 0; } static struct platform_driver platform_wdt_driver = { .driver = { .name = "watchdog", |
f37d193c7 watchdog: fix pla... |
262 |
.owner = THIS_MODULE, |
7d831bf59 [WATCHDOG] davinc... |
263 264 |
}, .probe = davinci_wdt_probe, |
b6bf291f1 [WATCHDOG] move p... |
265 |
.remove = __devexit_p(davinci_wdt_remove), |
7d831bf59 [WATCHDOG] davinc... |
266 |
}; |
b8ec61189 watchdog: convert... |
267 |
module_platform_driver(platform_wdt_driver); |
7d831bf59 [WATCHDOG] davinc... |
268 269 270 271 272 273 274 275 276 277 278 279 |
MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("DaVinci Watchdog Driver"); module_param(heartbeat, int, 0); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat period in seconds from 1 to " __MODULE_STRING(MAX_HEARTBEAT) ", default " __MODULE_STRING(DEFAULT_HEARTBEAT)); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
f37d193c7 watchdog: fix pla... |
280 |
MODULE_ALIAS("platform:watchdog"); |