I2C驱动实验:向设备树添加 I2C设备的设备节点信息

一.  简介

I2C设备驱动实验以 I.MX6U-ALPHA 开发板上的 AP3216C 这个三合一环境光传感器为例,通过 AP3216C讲解 一下,如何编写 Linux 下的 I2C 设备驱动程序。
因为 IMX6ULL所运行的 内核是支持设备树的,所以,本文来学习如何向设备树文件中添加 I2C设备节点信息,具体就是 添加 AP3216C设备的设备节点信息。

二. I2C驱动实验:AP3216C设备的硬件原理图

打开 AP3216C的硬件原理图,我这里打开 "IMX6ULL_ALPHA_V2.2(底板原理图).pdf",如下:

I2C是有两根线,一个是 SCL为时钟线,一个是SDA为数据线。

上图可以看出,AP3216C使用的 I2C1控制器,除了 I2C的这两条线外,还有一个AP_INT接口,这是个中断接口。本实验不用这个中断功能。

在硬件原理图中搜索 "I2C1_SCL"与 "I2C1_SDA"这两个接口,对应连接芯片的哪个PIN:

可以看出, "I2C1_SCL"使用的 UART4_TXD这个pin, "I2C1_SDA"使用的 UART4_RXD这个pin。

接下来就是找到这两个PIN,向设备树中添加 AP3216C设备的设备节点信息。

具体就是将这两个PIN配置为I2C功能,配置这两个PIN的器属性值,设置一些设备节点信息(例如,最重要的是 compatile属性)。

三.  向设备树添加 I2C设备(AP3216C)的设备节点信息

打开ubuntu系统,通过vscode 打开系统下 之前使用的内核源码(NXP官方提供)工程。

注意:这里开发板使用的Nand_flash版的ALPHA开发板,所以,对应的设备树文件(源文件)为 imx6ull-alientek-nand.dts。

1.  查看 i2c1 控制器节点

设备树文件 imx6ull-alientek-nand.dts有调用到 imx6ull-14x14-evk-gpmi-weim.dts文件,这两个文件中都没有 i2c设备节点,继续追溯到 imx6ull-14x14-evk.dts设备树文件。i2c1 设备节点就在 imx6ull-14x14-evk.dts 设备树文件中。

注意: imx6ull.dtsi设备树文件是 NXP官方编写的,虽然这里也有 i2c设备节点,不能在这个设备树文件中进行更改。

在 imx6ull-14x14-evk.dts设备树文件中查找到 i2c1控制器节点。

2.  向设备树添加 I2C设备(AP3216C)的设备节点信息

(1) 首先,添加按键的 pinctrl 节点

首先肯定是要修改 IO AP3216C 用到了 I2C1 接口, I.MX6U-ALPHA 开发板上的 I2C1 口使用到了 UART4_TXD UART4_RXD ,因此,肯定要在设备树里面设置这两个 IO
如果要用 AP3216C 的中断功能的话,还需要初始化 AP_INT 对应的 GIO1_IO01 这个 IO ,本章实验我们 不使用中断功能。因此,只需要设置 UART4_TXD UART4_RXD 这两个 IO
NXP 其实已经将 这两个 IO 设置好了,打开 imx6ull-14x14-evk.dts ,然后找到如下内容:
		pinctrl_i2c1: i2c1grp {
			fsl,pins = <
				MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
				MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
			>;
		};

pinctrl_i2c1 就是 I2C1 IO 节点,这里将 UART4_TXD UART4_RXD 这两个 IO 分别 复用为 I2C1_SCL I2C1_SDA ,电气属性都设置为 0x4001b8b0

(2)  其次,在 i2c1 节点追加 ap3216c 子节点

AP3216C 是连接到 I2C1 上的,因此需要在 i2c1 节点下添加 ap3216c 的设备子节点,在 imx6ull-14x14-evk.dts设备树 文件中找到 i2c1 节点,此节点默认内容如下:
&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";

	mag3110@0e {
		compatible = "fsl,mag3110";
		reg = <0x0e>;
		position = <2>;
	};

	fxls8471@1e {
		compatible = "fsl,fxls8471";
		reg = <0x1e>;
		position = <0>;
		interrupt-parent = <&gpio5>;
		interrupts = <0 8>;
	};
};

2 行, clock-frequency 属性为 I2C 频率,这里设置为 100KHz
4 行, pinctrl-0 属性指定 I2C 所使用的 IO 为示例代码 61.5.1.1 中的 pinctrl_i2c1 子节点。

7~11 行,mag3110 是个磁力计,NXP 官方的 EVK 开发板上接了 mag3110,因此 NXP i2c1 节点下添加了 mag3110 这个子节点。正点原子的 I.MX6U-ALPHA 开发板上没有用到 mag3110

13~19 行, NXP 官方 EVK 开发板也接了一个 fxls8471 ,正点原子的 I.MX6U-ALPHA 开发板同样没有此器件。
i2c1 节点里面原有的 mag3110 fxls8471 这两个 I2C 子节点删除,然后添加 ap3216c 子节点信息,完成以后的 i2c1 节点内容如下所示:
&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";

	ap3216c@1e {
		compatible = "alientek,ap3216c";
		reg = <0x1e>;
	};
};
7 行, ap3216c 子节点, @ 后面的“ 1e ”是 ap3216c 的器件地址。
8 行,设置 compatible 值为“ alientek,ap3216c ”。
9 行, reg 属性也是设置 ap3216c 器件地址的,因此 reg 设置为 0x1e。 可以通过AP3216C芯片的手册查询,即 AP3216C.pdf文档查到。

3. 编译设备树文件

打开终端进入 内核源码的根目录下,输入如下命令编译设备树文件:

make dtbs

这里可以编译生成新的设备树文件 mx6ull-alientek-nand.dtb(适用于Nand-Flash版ALPHA开发板)。接下来将设备树文件运行到开发板上,测试 设备节点是否添加好。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在I2C驱动中注册I2C设备节点是通过`i2c_new_device`函数来完成的。下面是一个示例代码,演示了如何在I2C驱动中注册一个I2C设备节点: ```c #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> static struct i2c_adapter *my_i2c_adapter; static struct i2c_client *my_i2c_client; static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { // 初始化I2C设备 my_i2c_client = client; // 设置设备信息 struct i2c_board_info board_info; strlcpy(board_info.type, "my_i2c_device", I2C_NAME_SIZE); // 设备类型 board_info.addr = client->addr; // I2C设备地址 // 其他设备信息设置... // 注册I2C设备 if (i2c_new_device(client->adapter, &board_info) == NULL) { dev_err(&client->dev, "Failed to register i2c device\n"); return -ENODEV; } // 其他初始化操作... return 0; } static int my_i2c_remove(struct i2c_client *client) { // 移除I2C设备 // 其他清理操作... return 0; } static const struct i2c_device_id my_i2c_id[] = { { "my_i2c_device", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, my_i2c_id); static struct i2c_driver my_i2c_driver = { .probe = my_i2c_probe, .remove = my_i2c_remove, .id_table = my_i2c_id, .driver = { .name = "my_i2c_driver", .owner = THIS_MODULE, }, }; static int __init my_i2c_init(void) { // 注册I2C驱动 my_i2c_adapter = i2c_get_adapter(0); return i2c_add_driver(&my_i2c_driver); } static void __exit my_i2c_exit(void) { // 注销I2C驱动 i2c_del_driver(&my_i2c_driver); i2c_put_adapter(my_i2c_adapter); } module_init(my_i2c_init); module_exit(my_i2c_exit); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("I2C Driver Example"); MODULE_LICENSE("GPL"); ``` 在上述示例中,我们在`my_i2c_probe`函数中使用`i2c_new_device`函数注册了一个新的I2C设备。首先,我们定义并初始化一个`struct i2c_board_info`结构体,设置设备的类型、地址等信息。然后,调用`i2c_new_device`函数,将适配器和设备信息作为参数传递给它,以创建一个新的I2C设备节点。 请注意,上述代码中的字符串"my_i2c_device"是示例的设备类型名称,你应该根据你的实际设备类型进行相应的更改。 通过这样的方式,在I2C驱动中注册I2C设备节点后,你可以使用I2C设备节点进行读写操作,以与该I2C设备进行通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值