转载--rk3399下iic,i2c驱动-----设备树

转载于:
https://blog.csdn.net/qq_33166886/article/details/83894814
前面说了iic在新内核下的一种方式,下面是第二种方式,这种方式在fireflyWiki教程里面有说明

代码如下

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
 
 
static int major;
static struct class *class;
static struct i2c_client *iic_client;
 
static int read_reg(const struct i2c_client *client, unsigned int *buf , unsigned char address)
{
	struct i2c_msg msg[2];
	int ret;
	unsigned char date1[2];
 
	msg[0].addr  = client->addr;  
	msg[0].buf   = &address;              
	msg[0].len   = 1;                     
	msg[0].flags = 0;                   
 
	msg[1].addr  = client->addr; 
	msg[1].buf   = date1;                 
	msg[1].len   = 2;                    
	msg[1].flags = I2C_M_RD;                   
 
	ret = i2c_transfer(client->adapter, msg, 2);
	if (ret > 0)
	{
		printk(KERN_INFO "date1 : %d date1 :%d\n",date1[0],date1[1]);
		*buf = (date1[0] << 8) | (date1[1]); 
		return 1;
	}
	else
		return -EIO;
}
 
 
static struct file_operations iic_fops = {
	.owner = THIS_MODULE,
 
};
 
static int iic_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
	int ret;
	unsigned int data = 0;
	iic_client = client;
		
	printk(KERN_INFO "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	major = register_chrdev(0, "iic", &iic_fops);
	class = class_create(THIS_MODULE, "iic");
	device_create(class, NULL, MKDEV(major, 0), NULL, "iic"); 
	ret = read_reg(iic_client,&data,0xff);
	printk(KERN_INFO "Device ID 0x%x\n",data);
	return 0;
}
 
static int iic_remove(struct i2c_client *client)
{
	printk(KERN_INFO "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	device_destroy(class, MKDEV(major, 0));
	class_destroy(class);
	unregister_chrdev(major, "iic");
		
	return 0;
}
 
static const struct i2c_device_id iic_id_table[] = {
	{ "iic_test", 0 },
	{}
};
static const struct of_device_id of_alc_match[] = {
	{ .compatible = "alc5651" },
	{  }
};
 
static struct i2c_driver iic_driver = {
	.driver	= {
		.name	= "rt5651_iic",
		.owner	= THIS_MODULE,
		.of_match_table	= of_alc_match,
	},
	.probe		= iic_probe,
	.remove		= iic_remove,
	.id_table	= iic_id_table,
};
 
static int iic_drv_init(void)
{
	printk(KERN_INFO "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	i2c_add_driver(&iic_driver);
	
	return 0;
}
 
static void iic_drv_exit(void)
{
	i2c_del_driver(&iic_driver);
}
 
 
module_init(iic_drv_init);
module_exit(iic_drv_exit);
MODULE_LICENSE("GPL");

makefile文件就不贴了,前一篇文章有说

dts文件中新增内容:

&i2c1 {
        status = "okay";
        i2c-scl-rising-time-ns = <300>;
        i2c-scl-falling-time-ns = <15>;
 
        rt5651: rt5651@1a {
                #sound-dai-cells = <0>;
                compatible = "realtek,rt5651";
                reg = <0x1a>;
                clocks = <&cru SCLK_I2S_8CH_OUT>;
                clock-names = "mclk";
                pinctrl-names = "default";
                pinctrl-0 = <&i2s_8ch_mclk>;
                spk-con-gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
        };
 
        alc5651: alc5651@1a{ //新增的内容
                status = "okay";
                compatible = "alc5651";
                reg = <0x1a>;//iic设备地址,不可忽略,必须写对
        };
 
};

一样,还是贴一下结果,注意,这里的模块里面没有iic_dev.ko,只有iic_dts.ko这个模块被加载

g3399:/storage/0000-0000 # ls
LOST.DIR                  cmd_test iic_dev.ko test.ko      
System Volume Information iic.ko   iic_dts.ko test_char.ko 
g3399:/storage/0000-0000 # insmod iic_dts.ko                                   
[  449.444537] /rk3399/source/g3399-v7-1-2-20180529/test_code/iic/iic_dts.c iic_drv_init 96
[  449.452793] /rk3399/source/g3399-v7-1-2-20180529/test_code/iic/iic_dts.c iic_probe 55
[  449.456078] dag3399:/storage/0000-0000 # te1 : 98 date1 :129
[  449.456099] Device ID 0x6281
 
g3399:/storage/0000-0000 # 
g3399:/storage/0000-0000 # 
g3399:/storage/0000-0000 # 
g3399:/storage/0000-0000 # lsmod
Module                  Size  Used by
iic_dts                 4050  0 
g3399:/storage/0000-0000 # 
<think>我们正在讨论的是RK3568平台的I2C接口启用问题,特别是激活I2C-3。根据提供的引用资料,我们可以总结出以下步骤和关键点: 1. **设备树配置**:RK3568使用设备树描述硬件,因此需要在设备树中配置I2C控制器(adapter)和具体的I2C设备(client)。引用[1]提到RK3568使用设备树取代了平台文件,因此我们需要修改设备树来启用I2C-3。 2. **驱动支持**:确保内核中包含了RK3568的I2C控制器驱动i2c-rk3x.c),该驱动提供了master_xfer等函数实现I2C传输(引用[2]和引用[5])。 3. **设备驱动匹配**:引用[3]提到i2c_bus总线会根据设备类型(i2c_client_type)调用相应的驱动probe函数。因此,我们需要在设备树中正确描述I2C设备,并确保驱动被加载。 4. **调试与问题排查**:引用[4]提供了一些调试方法,如检查电源、抓取I2C波形、排除总线冲突等。 **具体步骤:** **步骤1:修改设备树** 在设备树中启用I2C-3控制器,并添加所需的设备节点。通常,设备树文件位于`arch/arm64/boot/dts/rockchip/`目录下,具体文件可能为`rk3568-xxx.dtsi`或`rk3568-xxx.dts`。 例如,在设备树中找到I2C3的节点(可能为`i2c3`),将其状态改为`okay`,并添加挂载在该总线上的设备节点(如触摸屏、传感器等)。 ```dts &i2c3 { status = "okay"; clock-frequency = <400000>; // 设置I2C时钟频率,例如400kHz // 例如,添加一个触摸屏设备 ilitek_touch: ilitek@41 { compatible = "ilitek,ili2116"; reg = <0x41>; interrupt-parent = <&gpio0>; interrupts = <RK_PA0 IRQ_TYPE_EDGE_FALLING>; reset-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>; vdd-supply = <&vcc3v3_sys>; }; }; ``` **步骤2:配置内核驱动** 确保内核配置中启用了I2C控制器驱动(CONFIG_I2C_RK3X)以及具体的设备驱动(如触摸屏驱动)。在编译内核时,这些驱动需要被编译进内核或作为模块加载。 **步骤3:编译和更新设备树** 修改设备树后,需要重新编译设备树,并将生成的dtb文件更新到设备上。具体步骤取决于你的开发环境。 **步骤4:调试** 如果I2C设备未能正常工作,可以按照引用[4]中的方法进行调试: - 检查电源(VDD/VDD_I2C)是否正常。 - 使用示波器或逻辑分析仪抓取I2C波形,确认通信是否正常。 - 检查是否有其他设备占用同一I2C总线,导致冲突。 **步骤5:验证I2C设备** 在系统启动后,检查I2C总线是否被识别,设备是否被加载: - 使用`i2cdetect -l`命令查看所有I2C总线,确认I2C-3存在。 - 使用`i2cdetect -y 3`(假设I2C-3对应的总线编号是3)扫描总线上连接的设备地址。 **注意事项:** - 设备树中的I2C控制器节点名称可能因具体平台而异,请参考RK3568的文档或现有的设备树文件。 - 如果I2C设备是触摸屏(如引用[4]中的ilitek),确保驱动已正确加载,并检查中断和复位GPIO的配置。 通过以上步骤,应该能够在RK3568安卓设备上启用I2C-3接口并连接设备。 §§相关问题§§ 1. RK3568设备树I2C控制器的节点名称是什么? 2. 如何在内核中调试I2C传输问题? 3. 在RK3568上,如何配置I2C的时钟频率? 4. I2C设备驱动probe函数没有被调用,可能的原因有哪些?</think>### 如何在RK3568安卓设备上启用I2C接口并激活I2C-3 #### 一、核心步骤 1. **设备树配置** 修改设备树文件(`.dts`)启用I2C-3控制器: ```dts &i2c3 { status = "okay"; // 启用I2C-3总线 clock-frequency = <400000>; // 设置时钟频率(单位Hz) // 添加挂载设备节点(如触摸屏) ilitek_touch: ilitek@41 { compatible = "ilitek,ili2116"; reg = <0x41>; // I2C设备地址 interrupt-parent = <&gpio0>; interrupts = <RK_PA0 IRQ_TYPE_EDGE_FALLING>; }; }; ``` **关键点**: - `status = "okay"` 激活I2C-3总线[^1][^3] - `clock-frequency` 定义SCL时钟速率(标准模式100kHz,快速模式400kHz) - 设备节点需包含`compatible`属性匹配驱动[^3] 2. **内核驱动支持** 确保以下配置已启用: ```makefile CONFIG_I2C=y CONFIG_I2C_RK3X=y // RK3568专用I2C控制器驱动[^2][^5] CONFIG_TOUCHSCREEN_ILITEK=y // 示例:触摸屏驱动 ``` 驱动实现位于 `drivers/i2c/busses/i2c-rk3x.c`[^2][^5]。 3. **硬件检查** - 确认I2C-3引脚未被复用为GPIO(检查pinctrl配置) - 测量VDD/I2C供电电压(通常3.3V)[^4] - 使用示波器验证SCL/SDA波形(检测START/STOP信号)[^4] 4. **驱动加载验证** ```bash adb shell ls /sys/bus/i2c/devices/ # 查看I2C设备列表 adb shell cat /proc/interrupts # 检查设备中断注册 ``` #### 二、调试方法 1. **I2C传输调试** 使用内核函数 `i2c_transfer()` 发送消息[^2][^5]: ```c struct i2c_msg msg = { .addr = 0x41, // 设备地址 .flags = I2C_M_RD,// 读操作 .len = 2, // 数据长度 .buf = rx_buf // 接收缓冲区 }; int ret = i2c_transfer(adapter, &msg, 1); // 执行传输 ``` **返回值**:成功传输的消息数,错误时返回负值[^5]。 2. **常见问题排查** - **设备未响应**:检查设备地址、供电、I2C波形[^4] - **总线冲突**:移除同一总线上的其他设备[^4] - **驱动未绑定**:确认设备树`compatible`与驱动匹配[^3] #### 三、设备树驱动绑定流程 ```mermaid graph LR A[设备树声明] -->|compatible属性| B[i2c_bus总线] B -->|匹配| C[i2c_driver.probe] C --> D[注册i2c_client] D --> E[硬件操作] ``` - 总线通过`dev->type == i2c_client_type`识别设备[^3] - 成功匹配后调用`i2c_driver->probe()`初始化设备[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值