009-watchdog.patch 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. --- a/arch/arm/mach-sl2312/sl3516_device.c
  2. +++ b/arch/arm/mach-sl2312/sl3516_device.c
  3. @@ -76,9 +76,30 @@ static struct platform_device sata0_devi
  4. .resource = sl3516_sata0_resources,
  5. };
  6. +static struct resource sl351x_wdt_resources[] = {
  7. + [0] = {
  8. + .start = SL2312_WAQTCHDOG_BASE + 0x00,
  9. + .end = SL2312_WAQTCHDOG_BASE + 0x1C,
  10. + .flags = IORESOURCE_MEM,
  11. + },
  12. + [1] = {
  13. + .start = IRQ_WATCHDOG,
  14. + .end = IRQ_WATCHDOG,
  15. + .flags = IORESOURCE_IRQ,
  16. + },
  17. +};
  18. +
  19. +static struct platform_device sl351x_wdt = {
  20. + .name = "sl351x-wdt",
  21. + .id = -1,
  22. + .resource = sl351x_wdt_resources,
  23. + .num_resources = ARRAY_SIZE(sl351x_wdt_resources),
  24. +};
  25. +
  26. static struct platform_device *sata_devices[] __initdata = {
  27. &sata_device,
  28. &sata0_device,
  29. + &sl351x_wdt,
  30. };
  31. static int __init sl3516_init(void)
  32. --- a/drivers/char/watchdog/Kconfig
  33. +++ b/drivers/char/watchdog/Kconfig
  34. @@ -171,6 +171,17 @@ config EP93XX_WATCHDOG
  35. To compile this driver as a module, choose M here: the
  36. module will be called ep93xx_wdt.
  37. +config WATCHDOG_SL351X
  38. + tristate "SL351x Watchdog"
  39. + depends on WATCHDOG && ARCH_SL2312
  40. + help
  41. + This driver adds watchdog support for the integrated watchdog in the
  42. + SL351x processors (Farraday core). If you have one of these processors
  43. + and wish to have watchdog support enabled, say Y, otherwise say N.
  44. +
  45. + To compile this driver as a module, choose M here: the
  46. + module will be called sl351x_wdt.
  47. +
  48. config OMAP_WATCHDOG
  49. tristate "OMAP Watchdog"
  50. depends on ARCH_OMAP16XX || ARCH_OMAP24XX
  51. --- a/drivers/char/watchdog/Makefile
  52. +++ b/drivers/char/watchdog/Makefile
  53. @@ -36,6 +36,7 @@ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c241
  54. obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
  55. obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
  56. obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
  57. +obj-$(CONFIG_WATCHDOG_SL351X) += sl351x_wdt.o
  58. obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
  59. obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
  60. obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
  61. --- /dev/null
  62. +++ b/drivers/char/watchdog/sl351x_wdt.c
  63. @@ -0,0 +1,332 @@
  64. +#include <linux/module.h>
  65. +#include <linux/types.h>
  66. +#include <linux/fs.h>
  67. +#include <linux/mm.h>
  68. +#include <linux/errno.h>
  69. +#include <linux/init.h>
  70. +#include <linux/miscdevice.h>
  71. +#include <linux/watchdog.h>
  72. +#include <linux/platform_device.h>
  73. +#include <asm/uaccess.h>
  74. +#include <asm/arch/sl2312.h>
  75. +#include <asm/arch/hardware.h>
  76. +#include <asm/arch/irqs.h>
  77. +#include <asm/arch/watchdog.h>
  78. +#include <asm/io.h>
  79. +#include <linux/interrupt.h>
  80. +
  81. +#define WATCHDOG_TEST 1
  82. +#define PFX "sl351x-wdt: "
  83. +
  84. +#define _WATCHDOG_COUNTER 0x00
  85. +#define _WATCHDOG_LOAD 0x04
  86. +#define _WATCHDOG_RESTART 0x08
  87. +#define _WATCHDOG_CR 0x0C
  88. +#define _WATCHDOG_STATUS 0x10
  89. +#define _WATCHDOG_CLEAR 0x14
  90. +#define _WATCHDOG_INTRLEN 0x18
  91. +
  92. +static struct resource *wdt_mem;
  93. +static struct resource *wdt_irq;
  94. +static void __iomem *wdt_base;
  95. +static int wdt_margin = WATCHDOG_TIMEOUT_MARGIN; /* in range of 0 .. 60s */
  96. +
  97. +static int open_state = WATCHDOG_DRIVER_CLOSE;
  98. +static int wd_expire = 0;
  99. +
  100. +static void watchdog_enable(void)
  101. +{
  102. + unsigned long wdcr;
  103. +
  104. + wdcr = readl(wdt_base + _WATCHDOG_CR);
  105. + wdcr |= (WATCHDOG_WDENABLE_MSK|WATCHDOG_WDRST_MSK);
  106. +#ifdef WATCHDOG_TEST
  107. + wdcr |= WATCHDOG_WDINTR_MSK;
  108. +// wdcr &= ~WATCHDOG_WDRST_MSK;
  109. +#endif
  110. + wdcr &= ~WATCHDOG_WDCLOCK_MSK;
  111. + writel(wdcr, wdt_base + _WATCHDOG_CR);
  112. +}
  113. +
  114. +static void watchdog_set_timeout(unsigned long timeout)
  115. +{
  116. + timeout = WATCHDOG_TIMEOUT_SCALE * timeout;
  117. + writel(timeout, wdt_base + _WATCHDOG_LOAD);
  118. + writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
  119. +}
  120. +
  121. +static void watchdog_keepalive(void)
  122. +{
  123. + writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
  124. +}
  125. +
  126. +static void watchdog_disable(void)
  127. +{
  128. + unsigned long wdcr;
  129. +
  130. + wdcr = readl(wdt_base + _WATCHDOG_CR);
  131. + wdcr &= ~WATCHDOG_WDENABLE_MSK;
  132. + writel(wdcr, wdt_base + _WATCHDOG_CR);
  133. +}
  134. +
  135. +
  136. +#ifdef WATCHDOG_TEST
  137. +static irqreturn_t watchdog_irq(int irq, void *dev_id, struct pt_regs *regs)
  138. +{
  139. + unsigned int clear;
  140. +
  141. + writel(WATCHDOG_CLEAR_STATUS, wdt_base + _WATCHDOG_CLEAR);
  142. + printk(KERN_INFO PFX "Watchdog timeout, resetting system...\n");
  143. +
  144. + clear = __raw_readl(IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x0C);
  145. + clear &= 0x01;
  146. + __raw_writel(clear,IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x08);
  147. + wd_expire = 1;
  148. + return IRQ_HANDLED;
  149. +}
  150. +
  151. +#endif
  152. +
  153. +#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
  154. +static struct watchdog_info sl351x_wdt_ident = {
  155. + .options = OPTIONS,
  156. + .firmware_version = 0,
  157. + .identity = "sl351x Watchdog",
  158. +};
  159. +
  160. +struct file_operations watchdog_fops = {
  161. + .write = watchdog_write,
  162. + .read = watchdog_read,
  163. + .open = watchdog_open,
  164. + .release = watchdog_release,
  165. + .ioctl = watchdog_ioctl,
  166. +};
  167. +
  168. +static int watchdog_open(struct inode *inode, struct file *filp)
  169. +{
  170. + if (open_state == WATCHDOG_DRIVER_OPEN)
  171. + return -EBUSY;
  172. +
  173. + wd_expire = 0;
  174. +
  175. + watchdog_disable();
  176. + watchdog_set_timeout(wdt_margin);
  177. + watchdog_enable();
  178. +
  179. + printk(KERN_INFO PFX "watchog timer enabled, margin: %ds.\n", wdt_margin);
  180. + open_state = WATCHDOG_DRIVER_OPEN;
  181. +
  182. + return nonseekable_open(inode, filp);
  183. +}
  184. +
  185. +static int watchdog_release(struct inode *inode, struct file *filp)
  186. +{
  187. + watchdog_disable();
  188. +
  189. + open_state = WATCHDOG_DRIVER_CLOSE;
  190. + wd_expire = 0;
  191. + printk(KERN_INFO PFX "watchog timer disabled, margin: %ds.\n", wdt_margin);
  192. +
  193. + return 0;
  194. +}
  195. +
  196. +static ssize_t watchdog_read(struct file *filp, char *buf, size_t count, loff_t *off)
  197. +{
  198. + int i;
  199. + unsigned long val;
  200. +
  201. +
  202. + for(i=0;i< count;i++)
  203. + {
  204. + if ((i%4)==0)
  205. + val = *((unsigned long *)WATCHDOG_COUNTER);
  206. + buf[i] = (val & 0xFF);
  207. + val >>= 8;
  208. + }
  209. + return count;
  210. +}
  211. +
  212. +static ssize_t watchdog_write(struct file *filp, const char *buf, size_t len, loff_t *off)
  213. +{
  214. + /* Refresh the timer. */
  215. + if (len) {
  216. + watchdog_keepalive();
  217. + }
  218. + return len;
  219. +
  220. +}
  221. +
  222. +static int watchdog_ioctl(struct inode *inode, struct file *filp,
  223. + unsigned int cmd, unsigned long arg)
  224. +{
  225. + void __user *argp = (void __user *)arg;
  226. + int margin;
  227. +
  228. + switch(cmd)
  229. + {
  230. + case WDIOC_GETSUPPORT:
  231. + return copy_to_user(argp, &sl351x_wdt_ident,
  232. + sizeof(sl351x_wdt_ident)) ? -EFAULT : 0;
  233. +
  234. + case WDIOC_GETSTATUS:
  235. + case WDIOC_GETBOOTSTATUS:
  236. + return put_user(0, (int __user*)argp);
  237. +
  238. + case WDIOC_KEEPALIVE:
  239. + watchdog_keepalive();
  240. + return 0;
  241. +
  242. + case WDIOC_SETTIMEOUT:
  243. + if (get_user(margin, (int __user*)argp))
  244. + return -EFAULT;
  245. +
  246. + /* Arbitrary, can't find the card's limits */
  247. + if ((margin < 0) || (margin > 60))
  248. + return -EINVAL;
  249. +
  250. + // watchdog_disable();
  251. + wdt_margin = margin;
  252. + watchdog_set_timeout(margin);
  253. + watchdog_keepalive();
  254. + // watchdog_enable();
  255. +
  256. + /* Fall through */
  257. +
  258. + case WDIOC_GETTIMEOUT:
  259. + return put_user(wdt_margin, (int *)arg);
  260. +
  261. + default:
  262. + return -ENOIOCTLCMD;
  263. + }
  264. +}
  265. +
  266. +static struct miscdevice wd_dev= {
  267. + WATCHDOG_MINOR,
  268. + "watchdog",
  269. + &watchdog_fops
  270. +};
  271. +
  272. +static char banner[] __initdata = KERN_INFO "SL351x Watchdog Timer, (c) 2007 WILIBOX\n";
  273. +
  274. +static int sl351x_wdt_probe(struct platform_device *pdev)
  275. +{
  276. + struct resource *res;
  277. + int ret, size;
  278. + unsigned long wdcr;
  279. +
  280. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  281. + if (res == NULL) {
  282. + printk(KERN_INFO PFX "failed to get memory region resouce\n");
  283. + return -ENOMEM;
  284. + }
  285. +
  286. + size = (res->end-res->start)+1;
  287. +
  288. + wdt_mem = request_mem_region(res->start, size, pdev->name);
  289. + if (wdt_mem == NULL) {
  290. + printk(KERN_INFO PFX "failed to get memory region\n");
  291. + return -ENOENT;
  292. + }
  293. +
  294. + wdt_base = ioremap(res->start, size);
  295. + if (wdt_base == NULL) {
  296. + printk(KERN_INFO PFX "failed to ioremap() region\n");
  297. + return -EINVAL;
  298. + }
  299. +
  300. + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  301. + if (res == NULL) {
  302. + printk(KERN_INFO PFX "failed to get irq resource\n");
  303. + return -ENOENT;
  304. + }
  305. +
  306. + wdt_irq = res;
  307. +
  308. + ret = request_irq(res->start, watchdog_irq, 0, pdev->name, pdev);
  309. + if (ret != 0) {
  310. + printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
  311. + return ret;
  312. + }
  313. +
  314. + wdcr = readl(wdt_base + _WATCHDOG_CR);
  315. + if (wdcr & WATCHDOG_WDENABLE_MSK) {
  316. + printk(KERN_INFO PFX "Found watchdog in enabled state, reseting ...\n");
  317. + wdcr &= ~WATCHDOG_WDENABLE_MSK;
  318. + writel(wdcr, wdt_base + _WATCHDOG_CR);
  319. + }
  320. +
  321. + ret = misc_register(&wd_dev);
  322. +
  323. + return ret;
  324. +}
  325. +
  326. +static int sl351x_wdt_remove(struct platform_device *pdev)
  327. +{
  328. + if (wdt_base != NULL) {
  329. + iounmap(wdt_base);
  330. + wdt_base = NULL;
  331. + }
  332. +
  333. + if (wdt_irq != NULL) {
  334. + free_irq(wdt_irq->start, pdev);
  335. + release_resource(wdt_irq);
  336. + wdt_irq = NULL;
  337. + }
  338. +
  339. + if (wdt_mem != NULL) {
  340. + release_resource(wdt_mem);
  341. + wdt_mem = NULL;
  342. + }
  343. +
  344. + misc_deregister(&wd_dev);
  345. +
  346. + return 0;
  347. +}
  348. +
  349. +static void sl351x_wdt_shutdown(struct platform_device *dev)
  350. +{
  351. + watchdog_disable();
  352. +}
  353. +
  354. +#ifdef CONFIG_PM
  355. +static int sl351x_wdt_suspend(struct platform_device *dev, pm_message_t state)
  356. +{
  357. + watchdog_disable();
  358. +}
  359. +
  360. +static int sl351x_wdt_resume(struct platform_device *dev)
  361. +{
  362. + watchdog_set_timeout(wdt_margin);
  363. + watchdog_enable();
  364. +}
  365. +
  366. +#else
  367. +#define sl351x_wdt_suspend NULL
  368. +#define sl351x_wdt_resume NULL
  369. +#endif
  370. +
  371. +static struct platform_driver sl351x_wdt_driver = {
  372. + .probe = sl351x_wdt_probe,
  373. + .remove = sl351x_wdt_remove,
  374. + .shutdown = sl351x_wdt_shutdown,
  375. + .suspend = sl351x_wdt_suspend,
  376. + .resume = sl351x_wdt_resume,
  377. + .driver = {
  378. + .owner = THIS_MODULE,
  379. + .name = "sl351x-wdt",
  380. + },
  381. +};
  382. +
  383. +static int __init watchdog_init(void)
  384. +{
  385. + printk(banner);
  386. + return platform_driver_register(&sl351x_wdt_driver);
  387. +}
  388. +
  389. +static void __exit watchdog_exit(void)
  390. +{
  391. + platform_driver_unregister(&sl351x_wdt_driver);
  392. +}
  393. +
  394. +module_init(watchdog_init);
  395. +module_exit(watchdog_exit);