赞
踩
本章以Jetson AGX Orin为例讲解I2C watchdog驱动程序的编程,主要分为以下三个部分。
Block Diagram
SOC端的#pin脚定义
MCU端#pin脚定义
上图描述了linux I2C驱动框架,体系结构在linux中实现相当复杂。如何编写一个linux驱动程序呢?所谓Linux驱动个人认为主要是起承上启下的作用,对上提供接口API给内核,再由内核间接将接口提供给应用层,比如应用层访问/dev/watchdogX文件等;对下控制硬件设备。具体实现的流程套路如下:
1. 确定驱动结构:根据硬件设计结合分层/分离思想确定驱动的基本结构。
2. 确定驱动实例:驱动定义,初始化,注册,注销。
3. 向上提供接口:实现i2c设备的i2c_driver接口以及i2c设备对应的watchdog驱动
4. 向下控制硬件:根据寄存器配置方式实现控制逻辑。
驱动大致流程:
1) 加载驱动(int函数)
2) 添加i2c驱动
3) 匹配目标硬件设备
4) 探测probe函数
5) 注册watchdog设备
6) 实现watchdog操作集(start,stop,set_timeout等)
7) 注销watchdog设备
8) 卸载驱动
i2c_driver: 代表的一个i2c设备驱动,类似于platform_driver,在i2c_driver注册到内核且名称与设备树匹配一致就会进入到probe函数,驱动卸载时要进入remove函数。所以编写驱动需要将probe,remove和用于匹配硬件的driver进行填充。
- struct i2c_driver mcu_watchdog_driver = {
- .driver = {
- .name = "I2C MCU Watchdog",
- .owner = THIS_MODULE,
- .of_match_table = advwdt_dt_ids,
- },
- .probe = i2c_wtd_probe,
- .remove = i2c_wtd_remove,
- .id_table = advwdt_id,
-
- };
-
- static int __init watchdog_driver_init(void)
- {
- return i2c_add_driver(&mcu_watchdog_driver);
- }

of_match_table:用于匹配设备树信息,匹配的顺序of_match_table> acpi_match_table> id_table>name。
- static const struct of_device_id advwdt_dt_ids[] = {
- {.compatible = "stm,i2c-watchdog"},
- {}
- };
设备树:添加硬件信息,slave地址等
- hdr40_i2c1: i2c@c250000 {
- i2cmcu@58 {
- compatible = "stm,i2c-watchdog";
- reg = <0x58>;
- #address-cells = <1>;
- #size-cells = <0>;
- skip_mux_detect = "yes";
- vcc-supply = <&p3737_vdd_1v8_sys>;
- };
- };
i2c_client:描述挂接在硬件i2c总线上的设备的设备信息,即i2c设备的设备对象。
watchdog_device: watchdog子系统提供了一系列操作,不需要用户再次编写,只需要向相应的结构体填写设备信息。
主要函数:注册,注销。
- extern int watchdog_register_device(struct watchdog_device *);
- extern void watchdog_unregister_device(struct watchdog_device *);
自定义驱动私有数据结构体。
- struct mcu_wtd_data {
- struct watchdog_device wdd;
- struct i2c_client *client;
- };
实现探测probe函数。
- static int i2c_wtd_probe(struct i2c_client *client, const struct i2c_device_id *id)
- {
- struct mcu_wtd_data *wd_data;
- int ret = 0;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -ENODEV;
-
- wd_data = devm_kzalloc(&client->dev, sizeof(struct mcu_wtd_data), GFP_KERNEL);
- if (!wd_data)
- return -ENOMEM;
-
- wd_data->client = client;
- watchdog_set_drvdata(&wd_data->wdd, wd_data);
- i2c_set_clientdata(client, wd_data);
-
- wd_data->wdd.info = &jetson_mcu_watchdog_info;
- wd_data->wdd.ops = &jetson_mcu_watchdog_ops;
- wd_data->wdd.max_timeout = MAX_TIMEOUT;
- wd_data->wdd.min_timeout = MIN_TIMEOUT;
- wd_data->wdd.timeout = DEFAULT_TIMEOUT;
- wd_data->wdd.parent = &client->dev;
-
- ret = watchdog_register_device(&wd_data->wdd);
- if (ret) {
- dev_err(&client->dev, "failed to register watchdog device\n");
- return ret;
- }
- return 0;
- }

定义watchdog_ops操作函数。
- static const struct watchdog_ops jetson_mcu_watchdog_ops = {
- .owner = THIS_MODULE,
- .start = jetson_mcu_watchdog_start,
- .stop = jetson_mcu_watchdog_stop,
- //.ping = jetson_mcu_watchdog_ping,
- .set_timeout = jetson_mcu_watchdog_set_timeout,
- };
实现start,stop,set_timeout函数等。
- static int jetson_mcu_watchdog_start(struct watchdog_device *wdd)
- {
- struct mcu_wtd_data *wd_data = watchdog_get_drvdata(wdd);
- int ret = 0;
-
- ret = i2c_smbus_write_byte_data(wd_data->client, WATCHDOG_CONTROL_REG, WATCHDOG_ENABLE);
- if (ret < 0) {
- dev_err(&wd_data->client->dev, "failed to start watchdog: %d\n", ret);
- return ret;
- }
- return 0;
- }
-
- static int jetson_mcu_watchdog_stop(struct watchdog_device *wdd)
- {
- struct mcu_wtd_data *wd_data = watchdog_get_drvdata(wdd);
- int ret = 0;
-
- ret = i2c_smbus_write_byte_data(wd_data->client, WATCHDOG_CONTROL_REG, WATCHDOG_DISABLE);
- if (ret < 0) {
- dev_err(&wd_data->client->dev, "failed to stop watchdog: %d\n", ret);
- return ret;
- }
- return 0;
- }

注销watchdog函数
- static int i2c_wtd_remove(struct i2c_client *client)
- {
- struct mcu_wtd_data *wd_data = i2c_get_clientdata(client);
-
- watchdog_unregister_device(&wd_data->wdd);
-
- return 0;
- }
驱动卸载函数
- static void __exit watchdog_driver_exit(void)
- {
- i2c_del_driver(&mcu_watchdog_driver);
- }
至此,我们的i2c watchdog驱动开发流程已经完毕,接下来就是通过用户层程序使用ioctl()进行访问/dev/watchdog节点来调试。
参考链接:
https://blog.csdn.net/changqing1990/article/details/127511793?spm=1001.2014.3001.5502
https://www.kernel.org/doc/Documentation/watchdog/watchdog-kernel-api.txt
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。