项目中需要实现watchdog功能,研究了下系统中的watchdog。硬件watchdog使用芯片max6371,看芯片资料,结合硬件设计,发现需要控制的信号有两个,是系统的GPIO,GPIO1是使能watchdog的信号,连接到max6371的set2引脚 ,GPIO2是喂狗的信号,连接到max6371的wdi引脚。如下图:

系统使用linux内核版本4.9.75,内核配置CONFIG_MAX63XX_WATCHDOG=y 后,系统下未生成/dev/watchdog。 走读代码发下max63xx_wdt.c源码和硬件设计不符,不支持GPIO,源码注释中也有说明:

* This driver assumes the watchdog pins are memory mapped (as it is
 * the case for the Arcom Zeus). Should it be connected over GPIOs or
 * another interface, some abstraction will have to be introduced.

网上找了一些资料,有支持GPIO的补丁,参考补丁链接:https://lore.kernel.org/patchwork/patch/571616/,支持了GPIO的配置后,发现还是未生成/dev/watchdog 设备文件。经过调试发现,没有进入probe函数,所以没有注册。走读代码发现,驱动是以platform driver形式注册了驱动,但是没有注册platform device,因此不能进入probe。加上platform device add之后,可以生成/dev/watchdog了。

补丁:

diff -ruNa a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
--- a/drivers/watchdog/max63xx_wdt.c    2018-11-20 18:17:19.969287012 +0800
+++ b/drivers/watchdog/max63xx_wdt.c    2018-11-20 17:43:32.605287012 +0800
@@ -20,6 +20,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/watchdog.h>
+#include <linux/gpio.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
@@ -28,6 +29,7 @@
 
 #define DEFAULT_HEARTBEAT 60
 #define MAX_HEARTBEAT     60
+#define MAX63XX_DISABLED        3 
 
 static unsigned int heartbeat = DEFAULT_HEARTBEAT;
 static bool nowayout  = WATCHDOG_NOWAYOUT;
@@ -43,10 +45,25 @@
 
 static int nodelay;
 
+ /* struct max63xx_platform_data - MAX63xx connectivity info
+ * @wdi:    Watchdog Input GPIO number.
+ * @set0:    Watchdog SET0 GPIO number.
+ * @set1:    Watchdog SET1 GPIO number.
+ * @set2:    Watchdog SET2 GPIO number.
+ */
+struct max63xx_platform_data {
+    unsigned int wdi;
+    unsigned int set0, set1, set2;
+};
+
+static struct max63xx_platform_data st_max63xx_gpio_data = {382, 0, 0, 387};
+
 struct max63xx_wdt {
     struct watchdog_device wdd;
+    struct platform_device *pdev;
     const struct max63xx_timeout *timeout;
-
+    /* platform settings e.g. GPIO */
+    struct max63xx_platform_data *pdata;
     /* memory mapping */
     void __iomem *base;
     spinlock_t lock;
@@ -56,6 +73,9 @@
     void (*set)(struct max63xx_wdt *wdt, u8 set);
 };
 
+
+static struct max63xx_wdt *max63xx_wdt_data = NULL; 
+
 /*
  * The timeout values used are actually the absolute minimum the chip
  * offers. Typical values on my board are slightly over twice as long
@@ -116,129 +136,121 @@
     return NULL;
 }
 
-static int max63xx_wdt_ping(struct watchdog_device *wdd)
-{
-    struct max63xx_wdt *wdt = watchdog_get_drvdata(wdd);
-
-    wdt->ping(wdt);
-    return 0;
-}
-
-static int max63xx_wdt_start(struct watchdog_device *wdd)
-{
-    struct max63xx_wdt *wdt = watchdog_get_drvdata(wdd);
-
-    wdt->set(wdt, wdt->timeout->wdset);
-
-    /* check for a edge triggered startup */
-    if (wdt->timeout->tdelay == 0)
-        wdt->ping(wdt);
-    return 0;
-}
-
-static int max63xx_wdt_stop(struct watchdog_device *wdd)
-{
-    struct max63xx_wdt *wdt = watchdog_get_drvdata(wdd);
-
-    wdt->set(wdt, MAX6369_WDSET_DISABLED);
-    return 0;
-}
-
-static const struct watchdog_ops max63xx_wdt_ops = {
-    .owner = THIS_MODULE,
-    .start = max63xx_wdt_start,
-    .stop = max63xx_wdt_stop,
-    .ping = max63xx_wdt_ping,
-};
 
 static const struct watchdog_info max63xx_wdt_info = {
     .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
     .identity = "max63xx Watchdog",
 };
 
-static void max63xx_mmap_ping(struct max63xx_wdt *wdt)
-{
-    u8 val;
-
-    spin_lock(&wdt->lock);
-
-    val = __raw_readb(wdt->base);
-
-    __raw_writeb(val | MAX6369_WDI, wdt->base);
-    __raw_writeb(val & ~MAX6369_WDI, wdt->base);
-
-    spin_unlock(&wdt->lock);
-}
-
-static void max63xx_mmap_set(struct max63xx_wdt *wdt, u8 set)
-{
-    u8 val;
-
-    spin_lock(&wdt->lock);
-
-    val = __raw_readb(wdt->base);
-    val &= ~MAX6369_WDSET;
-    val |= set & MAX6369_WDSET;
-    __raw_writeb(val, wdt->base);
-
-    spin_unlock(&wdt->lock);
-}
-
-static int max63xx_mmap_init(struct platform_device *p, struct max63xx_wdt *wdt)
-{
-    struct resource *mem = platform_get_resource(p, IORESOURCE_MEM, 0);
-
-    wdt->base = devm_ioremap_resource(&p->dev, mem);
-    if (IS_ERR(wdt->base))
-        return PTR_ERR(wdt->base);
+static int max63xx_gpio_ping(struct watchdog_device *wdev) 
+{ 
+        max63xx_wdt_data = watchdog_get_drvdata(wdev); 
+        
+        gpio_set_value(max63xx_wdt_data->pdata->wdi, 1); 
+        gpio_set_value(max63xx_wdt_data->pdata->wdi, 0); 

+        return 0; 
+} 

+static inline void max63xx_gpio_set(struct watchdog_device *wdev, u8 set) 
+{ 
+        max63xx_wdt_data = watchdog_get_drvdata(wdev); 

+        gpio_set_value(max63xx_wdt_data->pdata->set2, 1); 
+} 

+static int max63xx_gpio_start(struct watchdog_device *wdev) 
+{ 
+        max63xx_wdt_data = watchdog_get_drvdata(wdev); 
+        
+        gpio_set_value(max63xx_wdt_data->pdata->set2, 1); 
+        
+        /* Check for an edge triggered startup */ 
+        if (max63xx_wdt_data->timeout->tdelay == 0) 
+                max63xx_gpio_ping(wdev); 
+        return 0; 
+} 

+static int max63xx_gpio_stop(struct watchdog_device *wdev) 
+{ 
+        max63xx_wdt_data = watchdog_get_drvdata(wdev); 
+        gpio_set_value(max63xx_wdt_data->pdata->set2, 0); 
+     return 0; 
+} 

+static const struct watchdog_ops max63xx_wdt_ops = {
+    .owner = THIS_MODULE,
+    .start = max63xx_gpio_start,
+    .stop = max63xx_gpio_stop,
+    .ping = max63xx_gpio_ping,
+};    
+ static int max63xx_gpio_init(struct platform_device *p, struct max63xx_wdt *wdt)
+ {
+    int err;
 
-    spin_lock_init(&wdt->lock);
+    pinctrl_free_gpio(wdt->pdata->wdi);
+    err = gpio_request_one( wdt->pdata->wdi, GPIOF_OUT_INIT_LOW, "max63xx_wdt WDI");
+    if (err)
+        return err;
 
-    wdt->ping = max63xx_mmap_ping;
-    wdt->set = max63xx_mmap_set;
+    pinctrl_free_gpio(wdt->pdata->set2);
+    err = gpio_request_one(wdt->pdata->set2, GPIOF_OUT_INIT_LOW, "max63xx_wdt SET2");
+    if (err)
+        return err;
+    
+    wdt->ping = max63xx_gpio_ping;
+    wdt->set = max63xx_gpio_set;
     return 0;
 }
-
 static int max63xx_wdt_probe(struct platform_device *pdev)
 {
-    struct max63xx_wdt *wdt;
-    struct max63xx_timeout *table;
-    int err;
-
-    wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
-    if (!wdt)
-        return -ENOMEM;
-
-    table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
+     struct max63xx_wdt *wdt;
+     struct max63xx_timeout *table;
+     int err;

+     wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+     if (!wdt)
+         return -ENOMEM;

+     table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
+     if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+         heartbeat = DEFAULT_HEARTBEAT;
+
+     wdt->timeout = max63xx_select_timeout(table, heartbeat);
+     if (!wdt->timeout) {
+         dev_err(&pdev->dev, "unable to satisfy %ds heartbeat request\n",
+             heartbeat);
+         return -EINVAL;
+     }
 
+    wdt->pdata = dev_get_platdata(&pdev->dev);
     if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
         heartbeat = DEFAULT_HEARTBEAT;
-
     wdt->timeout = max63xx_select_timeout(table, heartbeat);
     if (!wdt->timeout) {
         dev_err(&pdev->dev, "unable to satisfy %ds heartbeat request\n",
             heartbeat);
         return -EINVAL;
     }
+    /* GPIO or memory mapped? */
 
-    err = max63xx_mmap_init(pdev, wdt);
+    wdt->pdata = &st_max63xx_gpio_data;
+
+    err =  max63xx_gpio_init(pdev, wdt);
     if (err)
         return err;
-
+    
     platform_set_drvdata(pdev, &wdt->wdd);
     watchdog_set_drvdata(&wdt->wdd, wdt);
-
     wdt->wdd.parent = &pdev->dev;
     wdt->wdd.timeout = wdt->timeout->twd;
     wdt->wdd.info = &max63xx_wdt_info;
     wdt->wdd.ops = &max63xx_wdt_ops;
-
     watchdog_set_nowayout(&wdt->wdd, nowayout);
 
     err = watchdog_register_device(&wdt->wdd);
     if (err)
         return err;
-
     dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
          wdt->timeout->twd, wdt->timeout->tdelay);
     return 0;
@@ -268,11 +280,52 @@
     .remove        = max63xx_wdt_remove,
     .id_table    = max63xx_id_table,
     .driver        = {
-        .name    = "max63xx_wdt",
+        .name    = "max6371_wdt",
     },
 };
+static int __init max63xx_wdt_init_module(void)
+{
+    int err;
+    
+    pr_info("Intel max63xx WatchDog Timer Driver \n" );
+
+    err = platform_driver_register(&max63xx_wdt_driver);
+    pr_info("Intel max63xx WatchDog Timer Driver err %d\n", err);
+    if (err)
+        return err;
 
-module_platform_driver(max63xx_wdt_driver);
+    max63xx_wdt_data = kzalloc(sizeof(struct max63xx_wdt), GFP_KERNEL);
+    if (!max63xx_wdt_data) {
+        err = -ENOMEM;
+        platform_driver_unregister(&max63xx_wdt_driver);
+        return err;
+    }
+
+    
+    max63xx_wdt_data->pdev = platform_device_register_simple("max6371_wdt", -1, NULL, 0);
+    if (IS_ERR(max63xx_wdt_data->pdev)) {
+        err = PTR_ERR(max63xx_wdt_data->pdev);
+        platform_driver_unregister(&max63xx_wdt_driver);
+        kfree(max63xx_wdt_data);
+        return err;
+    }
+
+    return 0;
+}
+
+static void __exit max63xx_wdt_cleanup_module(void)
+{
+    platform_device_unregister(max63xx_wdt_data->pdev);
+    platform_driver_unregister(&max63xx_wdt_driver);
+    pr_info("Watchdog Module Unloaded\n");
+
+    
+}
+
+module_init(max63xx_wdt_init_module);
+module_exit(max63xx_wdt_cleanup_module);
+
+//module_platform_driver(max63xx_wdt_driver);
 
 MODULE_AUTHOR("Marc Zyngier <maz@misterjones.org>");
 MODULE_DESCRIPTION("max63xx Watchdog Driver");
@@ -293,3 +346,4 @@
          "(max6373/74 only, default=0)");
 
 MODULE_LICENSE("GPL v2");
+

看了一些linux内核的watchdog的驱动都是max63xx_wdt.c驱动类型,注册了platform的driver,但并没有注册设备驱动,是如何进入probe函数呢?这点值得研究?

linux下 gpio ma63xx_wdt.c驱动相关推荐

  1. 南京邮电大学嵌入式系统开发实验5:嵌入式Linux下LED报警灯驱动设计及编程

    实验5  嵌入式Linux下LED报警灯驱动设计及编程 一.实验目的 理解驱动本质,掌握嵌入式Linux系统下驱动开发相关知识,包括端口寄存器访问.接口函数编写.和文件系统挂接.注册及相关应用编程等知 ...

  2. 【全志T113-S3_100ask】15-2 linux系统gpio模拟spi驱动屏幕——ILI9341

    [全志T113-S3_100ask]15-2 linux系统gpio模拟spi驱动屏幕--ILI9341 背景 (一)查阅参考文档 (二)使能内核模块 (三)修改设备树 (四)测试 (五)后语 背景 ...

  3. Linux下的USB总线驱动 mouse

    Linux下的USB总线驱动(03)--USB鼠标驱动 usbmouse.c USB鼠标驱动 usbmouse.c 原文链接:http://www.linuxidc.com/Linux/2012-12 ...

  4. *Linux下的USB总线驱动 u盘驱动分析*

    Linux下的USB总线驱动(三) u盘驱动分析 版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127 https://www.xuebuyuan.com/13 ...

  5. 在Fedora 16 linux下安装USB无线网卡驱动88x2bu

    在Fedora 16 linux下安装USB无线网卡驱动88x2bu USB无线网卡翼联EP-AC1610兼容linux系统 我之前已经买了一个USB无线网卡是水星mw150us,但是没有linux驱 ...

  6. linux 安装水星无线网卡驱动,Linux下安装RTL8188CE网卡驱动(Mercury MW150U)

    先说明下我的系统: kernel: 3.0.0-32-generic 今天买了个无线网卡Mercury 150Mbps MW150U系列,我发现在我的笔记本的Ubuntu 12.10下不用安装驱动就能 ...

  7. 如何编写Linux 下的 USB 键盘驱动

     如何编写Linux 下的 USB 键盘驱动 1. 指定 USB 键盘驱动所需的头文件: #include <linux/kernel.h>/*内核头文件,含有内核一些常用函数的原型定 ...

  8. 什么是 Linux 下的 platform 设备驱动

    Linux下的字符设备驱动一般都比较简单,只是对IO进行简单的读写操作.但是I2C.SPI.LCD.USB等外设的驱动就比较复杂了,需要考虑到驱动的可重用性,以避免内核中存在大量重复代码,为此人们提出 ...

  9. Linux下PCI转串口卡驱动安装方法

    Linux下PCI转串口卡驱动安装方法 ----------------------------------- 由于公司产品要做行业市场,而产品与行业用户间PC的通讯为RS232串口方式.而行业用户那 ...

最新文章

  1. python操作微信电脑版_Python使用itchat模块实现简单的微信控制电脑功能示例
  2. 配置错误定义了重复的“system.web.extensions/scripting/scriptResourceHandler” 解决办法...
  3. JavaScript实现MaximumSubarray最大子阵列(Brute Force蛮力解决方案)算法(附完整源码)
  4. 提高调试.net cf程序效率一些技巧
  5. 分布式版本控制系统Git的安装与使用(作业2)
  6. java 子类 父类 转换_Java子类与父类之间的类型转换
  7. Spring Boot 学习之,数据库一 Spring-Data-Jpa 初探
  8. 编辑距离算法(C#版本)
  9. 二叉搜索树的第 k 大节点
  10. 多线程之join用法
  11. java mime上传_JavaWeb中实现文件上传的方式有哪些?
  12. 非功能测试之界面测试和易用性测试
  13. c语言数组的斐波那契数列
  14. z8350mini盒子装fedora无线wifi命令研究
  15. cf黑机器多久解除_[CF]黑机器码过无限提示一分钟强制踢出游戏的方法
  16. 太阳能计算机屏幕是什么材质,电脑显示器表面是什么材质的 什么是液晶玻璃...
  17. SEO利器 - 网页内容监控之百度自动推送
  18. ajax聊天室创建群聊,js+node.js+socket.io实现聊天功能(私聊,创建群聊)
  19. python将html转换成excel_Python将HTML格式文件中字段提取到EXCEL表的方法
  20. 使用Libxml2操作XML文档

热门文章

  1. 零基础编程者初学python须知
  2. 谈谈Unity对于手柄的支持
  3. 抽屉有源电力滤波器谐波治理
  4. ssm+微信小程序基于微信小程序的社区老人健康管理服务系统的设计与实现毕业设计源码011513
  5. 松下电器IT经理谈项目管理六点心得
  6. 【USACO】双数? 单数?
  7. 微信小程序_快递查询
  8. 企业邮箱忘了密码怎么办?不要怕
  9. 移动互联网,是破坏性创新吗?
  10. python分析人口出生率代码_身份证号码各位数字的含义以及计算校验位的python代码...