05day02wdt

  1 #include <linux/module.h>
  2 #include <linux/init.h>
  3 #include <linux/kernel.h>
  4 
  5 #include <mach/regs-clock.h> //EXYNOS4_CLKGATE_IP_PERIR
  6 #include <mach/map.h> //EXYNOS4_PA_WATCHDOG
  7 #include <linux/ioport.h> //request_mem_region
  8 #include <linux/io.h> //ioremap
  9 #include <linux/interrupt.h> //request_irq
 10 #include <mach/irqs.h> //EXYNOS4_IRQ_WDT
 11 
 12 #include <linux/miscdevice.h>
 13 #include <linux/fs.h>
 14 
 15 #include "wdt.h"
 16 
 17 //内核里已经有看门狗驱动,为了不冲突,必须关闭内核中的看门狗驱动
 18 //make menuconfig -> Device Drivers -> S3C2410 Watchdog 关闭
 19 
 20 #define DEVNAME "ldm"
 21 
 22 #define CLKGATE_IP_PERIR (*(volatile u32*)EXYNOS4_CLKGATE_IP_PERIR)
 23 
 24 enum {
 25     PCLK = 100000000, //100MHZ
 26     PRESCALER = 99, //1级分频为100分频
 27     DIV_FACTOR = 0b11, //2级分频为128分频
 28     WDT_HZ = PCLK / (PRESCALER + 1) / (16 << DIV_FACTOR),
 29 };
 30 
 31 struct ldm_info {
 32     struct miscdevice dev;
 33     struct file_operations ops;
 34 };
 35 static struct ldm_info ldm;
 36 
 37 struct wdt_reg {
 38     u32 con, dat, cnt, clrint;
 39 };
 40 static struct wdt_reg *reg;
 41 
 42 static long ldm_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 43 {
 44     switch (cmd) {
 45     case WDT_ON:
 46         if (arg) {
 47             reg->con |= 1 << 5;
 48         } else {
 49             reg->con &= ~(1 << 5);
 50         }
 51         break;
 52     case WDT_INTERVAL:
 53         reg->dat = WDT_HZ * arg / 1000;
 54         reg->cnt = WDT_HZ * arg / 1000;
 55         break;
 56     case WDT_RESET:
 57         reg->con |= 1;
 58         break;
 59     case WDT_INTERRUPT:
 60         reg->con &= ~1;
 61         reg->con |= 1 << 2;
 62         break;
 63     default:
 64         break;
 65     }
 66 
 67     return 0;
 68 }
 69 
 70 static irqreturn_t wdt_handler(int irqno, void *data)
 71 {
 72     printk("%s:%s, %d
", __FILE__, __FUNCTION__, __LINE__);
 73 
 74     //清除中断标志
 75     reg->clrint = 0x1234;
 76     return IRQ_HANDLED;
 77 }
 78 
 79 static int test_init(void)
 80 {
 81     int ret = 0;
 82 
 83     printk("%s:%s, %d
", __FILE__, __FUNCTION__, __LINE__);
 84 
 85     ldm.dev.minor = MISC_DYNAMIC_MINOR; //次设备号
 86     ldm.dev.name = DEVNAME;
 87     ldm.dev.fops = &ldm.ops;
 88     ldm.ops.unlocked_ioctl = ldm_ioctl;
 89 
 90     ret = misc_register(&ldm.dev);
 91     if (ret < 0) {
 92         printk(KERN_ERR "misc_register failed
");
 93         goto err_misc_register;
 94     }
 95 
 96     //根据4412手册P446表格,可知,wdt位于PERI_R总线,时钟源是100MHZ
 97 
 98     //打开wdt所在总线的时钟使能开关,4412手册P487
 99     CLKGATE_IP_PERIR |= 1 << 14;
100 
101     //申请寄存器的访问范围,通过/proc/iomem
102     if (!request_mem_region(EXYNOS4_PA_WATCHDOG, sizeof(struct wdt_reg), DEVNAME)) {
103         ret = -EBUSY;
104         printk(KERN_ERR "request_mem_region failed
");
105         goto err_request_mem_region;
106     }
107 
108     //映射寄存器,得到虚拟地址
109     reg = ioremap(EXYNOS4_PA_WATCHDOG, sizeof(struct wdt_reg));
110 
111     //申请中断
112     ret = request_irq(EXYNOS4_IRQ_WDT, wdt_handler, 0, DEVNAME, NULL);
113     if (ret < 0) {
114         printk(KERN_ERR "request_irq failed
");
115         goto err_request_irq;
116     }
117 
118     reg->dat = WDT_HZ / 2;
119     reg->cnt = WDT_HZ / 2;
120     reg->con = PRESCALER << 8 | DIV_FACTOR << 3 | 1 << 2;
121 
122     return 0;
123 
124 err_request_irq:
125     iounmap(reg);
126     release_mem_region(EXYNOS4_PA_WATCHDOG, sizeof(struct wdt_reg));
127 err_request_mem_region:
128     CLKGATE_IP_PERIR &= ~(1 << 14);
129     misc_deregister(&ldm.dev);
130 err_misc_register:
131     return ret;
132 }
133 
134 static void test_exit(void)
135 {
136     printk("%s:%s, %d
", __FILE__, __FUNCTION__, __LINE__);
137 
138     reg->con &= ~(1 << 5);
139 
140     free_irq(EXYNOS4_IRQ_WDT, NULL);
141     iounmap(reg);
142     release_mem_region(EXYNOS4_PA_WATCHDOG, sizeof(struct wdt_reg));
143 
144     //关闭wdt所在总线的时钟使能开关
145     CLKGATE_IP_PERIR &= ~(1 << 14);
146 
147     misc_deregister(&ldm.dev);
148 }
149 
150 module_init(test_init);
151 module_exit(test_exit);
152 
153 MODULE_LICENSE("GPL");

.h

 1 #pragma once
 2 
 3 #include <linux/ioctl.h> //实际头文件是linux/asm-generic/ioctl.h
 4 
 5 //参考内核文档documentation/ioctl/ioctl-number.txt和ioctl-decoding.txt
 6 
 7 #define WDT_ON _IOW('l', 1, int)
 8 #define WDT_INTERVAL _IOW('l', 2, unsigned int)
 9 #define WDT_RESET _IO('l', 3)
10 #define WDT_INTERRUPT _IO('l', 4)

.app

 1 #include <stdio.h>
 2 #include <fcntl.h>
 3 #include <unistd.h>
 4 #include <stdlib.h>
 5 #include <string.h>
 6 
 7 #include "wdt.h"
 8 
 9 int main(int argc, char **argv)
10 {
11     if ((argc != 3) && (argc != 4)) {
12         fprintf(stderr, "Usage: cmd <device file> <request> [interval second]
request: on off reset interrupt interval
");
13         return -1;
14     }
15 
16     int fd = open(argv[1], O_RDWR);
17     if (fd < 0) {
18         perror("open device");
19         goto err_open;
20     }
21 
22     if (!strcmp(argv[2], "on")) {
23         ioctl(fd, WDT_ON, 1);
24     } else if (!strcmp(argv[2], "off")) {
25         ioctl(fd, WDT_ON, 0);
26     } else if (!strcmp(argv[2], "reset")) {
27         ioctl(fd, WDT_RESET);
28     } else if (!strcmp(argv[2], "interrupt")) {
29         ioctl(fd, WDT_INTERRUPT);
30     } else if (!strcmp(argv[2], "interval")) {
31         ioctl(fd, WDT_INTERVAL, atoi(argv[3]));
32     } else {
33         fprintf(stderr, "unknown request %s
", argv[2]);
34     }
35 
36     close(fd);
37 
38     return 0;
39 
40 err_open:
41     return -1;
42 }
原文地址:https://www.cnblogs.com/baoshulin/p/6477020.html