• 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 }
  • 相关阅读:
    Silverlight Control(五)TimePicker
    《ASP.NET Core 3框架揭秘》笔记
    Hyper-V初体验
    debian初体验
    异步编程-编程指南
    Oracle查询优化读书笔记
    设计原则
    日志管理
    Git在Vs中的使用
    SVN使用备注
  • 原文地址:https://www.cnblogs.com/baoshulin/p/6477020.html
Copyright © 2020-2023  润新知