驱动版本的i2cdetect

本文介绍了一种用于检测I2C设备的驱动程序。该驱动可通过写入/proc/i2cdetectall来探测所有I2C地址,或通过写入/proc/i2cdetect来探测单条总线上的I2C地址。对于未检测到的地址,文章建议检查硬件电路或设备状态。

       这里写了一个驱动版本的i2cdect。其中先写/proc/i2cdetectall节点,然后读可以探测所有的i2c地址,写节点/proc/i2cdetect然后读可以探测单条总线的i2c地址。对于检测不到的i2c地址,可重新看下芯片手册或者检查硬件电路(如芯片有没有上电(摄像头地址需要需要在工作时),i2c引脚配置,dts注册了相应的i2c总线)。

原理:往i2c总线的发地址数据,如果应答了表示该地址存在。

源码如下

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/i2c.h>
#include <linux/delay.h>

//i2cdetect all
//echo 0 > /proc/i2cdetectall
//cat  /proc/i2cdetectall

//i2cdect i2_n address
//echo n > /proc/i2cdetect
//cat /proc/i2cdetect
unsigned char tbuf=0;
unsigned int i2c_bus;
unsigned int i2c_bus_count=0;
unsigned int i2c_bus_list[20];
unsigned char i2c_addr[256];

struct i2c_msg msg={
	.flags = 0,
	.buf   = &tbuf,
	.len=1,
};

static int i2c_detect_show(struct seq_file *m, void *v)
{
	unsigned char addr;
	seq_printf(m,"found i2c_%d address:\n",i2c_bus);
	for(addr=0x1;addr<0x80;addr++)
	{	
		if(i2c_addr[addr]!=0xff)
			seq_printf(m,"0x%x ",i2c_addr[addr]);
	}
	seq_printf(m,"\n");
	return 0;
}

ssize_t i2c_detect_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
	
    	int addr;
	int ret;
	struct i2c_adapter *adapter;
	memset(i2c_addr,0xff,sizeof(i2c_addr));
	i2c_bus=simple_strtoul(buffer,NULL,10);
	printk("i2c_bus=%d\n",i2c_bus);
    	adapter = i2c_get_adapter(i2c_bus); 
    	if (!adapter) {
        	printk("get i2c_%d adapter err\n",i2c_bus);  
        	return -ENODEV;
    	} else {
        	printk("get i2c_%d adapter ok\n",i2c_bus);
    	}
	for(addr=0x1;addr<0x80;addr++){
		msg.addr=addr;
		ret=i2c_transfer(adapter, &msg, 1);
		if(ret>0)
		{
			printk("found i2c addr 0x%0x\n",addr);
			i2c_addr[addr]=addr;
		}
	};
	i2c_put_adapter(adapter); 
	return count;
}

//0xff addr1 addr2 0xff addr3 addr4 0xff
static int i2c_detect_all_show(struct seq_file *m, void *v)
{
	int i=0;
	int j=0;
	for(i=0;i<i2c_bus_count;i++)
	{
		seq_printf(m,"i2c_%d address:\n",i2c_bus_list[i]);
		j++;
		while(i2c_addr[j]!=0xff)
		{	
			seq_printf(m,"0x%x ",i2c_addr[j]);
			j++;
		}
		seq_printf(m,"\n");
	}	
	return 0;
}

ssize_t i2c_detect_all_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
	int i;
	int ret;
	int addr;
	int addr_count=0;
	struct i2c_adapter *adapter;
	memset(i2c_addr,0xff,sizeof(i2c_addr));
	for(i=0;i<i2c_bus_count;i++)
	{
    		adapter = i2c_get_adapter(i2c_bus_list[i]); 
    		if (!adapter) {
        		printk("get i2c-%d adapter err\n",i2c_bus);  
        		return -ENODEV;
    		} else {
        		printk("get i2c-%d adapter ok\n",i2c_bus);
    		}
		addr_count++;
		for(addr=0x1;addr<0x80;addr++){
			msg.addr=addr;
			ret=i2c_transfer(adapter, &msg, 1);
			if(ret>0)
			{
				printk("found i2c-%d address  0x%0x\n",i2c_bus_list[i],addr);
				i2c_addr[addr_count++]=addr;
			}
		};
		i2c_put_adapter(adapter); 
	}
	return count;
}

static int i2c_detect_open(struct inode *inode, struct file *file)
{	
	return single_open(file, i2c_detect_show, NULL);
}

static int i2c_detect_all_open(struct inode *inode, struct file *file)
{	
	return single_open(file, i2c_detect_all_show, NULL);
}

static const struct file_operations i2c_detect_fops = 
{
	.owner   = THIS_MODULE,
	.open    = i2c_detect_open,
	.read    = seq_read,
	.write   = i2c_detect_write,
};

static const struct file_operations i2c_detect_all_fops = 
{
	.owner   = THIS_MODULE,
	.open    = i2c_detect_all_open,
	.read    = seq_read,
	.write   = i2c_detect_all_write,
};

void i2c_bus_detect(void)
{
	int i;
	struct i2c_adapter *adapter;
	memset(i2c_bus_list,0,sizeof(i2c_bus_list));
	for(i=0;i<20;i++)
	{
		adapter=i2c_get_adapter(i);
		if(adapter)
		{
			i2c_bus_list[i2c_bus_count++]=i;
			i2c_put_adapter(adapter);
		}
	}
	printk("i2c bus %d\n",i2c_bus_count);
	for(i=0;i<i2c_bus_count;i++)
		printk("found i2c-%d\n",i2c_bus_list[i]);
					
}
static int __init i2c_detect_init(void)
{
	i2c_bus_detect();
	memset(i2c_addr,0xff,sizeof(i2c_addr));
	proc_create("i2cdetect", S_IRWXUGO, NULL, &i2c_detect_fops);
	proc_create("i2cdetectall", S_IRWXUGO, NULL, &i2c_detect_all_fops);
	return 0;
}

static void __exit i2c_detect_exit(void)
{
	remove_proc_entry("i2cdetect", NULL);	
}

module_init(i2c_detect_init);  
module_exit(i2c_detect_exit);  
MODULE_AUTHOR("www");
MODULE_LICENSE("GPL");

将该驱动编译成模块(https://blog.youkuaiyun.com/mike8825/article/details/50495902),很方便来检测i2c设备。

应用层的i2cdetect(https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值