|
在工作過程中,意外發(fā)現(xiàn)一種很靈活的 I2C 設(shè)備偵測方式,特別有意思,此種方式可以實(shí)現(xiàn)無論 I2C 設(shè)備掛在哪一條 I2C 總線上,都能夠輕松找到該 I2C 設(shè)備,利用這種方式可以做到智能檢測設(shè)備,即使硬件更換 I2C 總線也不需要修改驅(qū)動程序。為了方便日后調(diào)試,寫了一個小驅(qū)動程序,用于通過往設(shè)備節(jié)點(diǎn)寫 I2C 設(shè)備地址來檢測 I2C 設(shè)備。
寫完之后在百度搜索了一下,看是否還有其他的方式,還真有:http://blog.csdn.net/yuanlulu/article/details/6557901
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/sysctl.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <linux/wakelock.h>
#include <linux/slab.h>
#define __ISDEBUG__
#include <linux/zhc_public.h>
#define LMX_I2C_DETECT_DEVICE_NAME "zhc_i2c_detect"
// 此處可以寫多個
static unsigned short s_Normal_I2c[] = {0x35, I2C_CLIENT_END}; // 芯片地址
/*
struct i2c_board_info {
char type[I2C_NAME_SIZE];
unsigned short flags;
unsigned short addr;
void *platform_data;
struct dev_archdata *archdata;
struct device_node *of_node;
struct acpi_dev_node acpi_node;
int irq;
int comp_addr_count;
struct i2c_comp_address *comp_addrs;
unsigned long irq_flags;
};
*/
/**************************** I2C 設(shè)備驅(qū)動框架 ****************************/
static int i2c_detect_Detect(struct i2c_client *client, struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
// 如果 I2C 設(shè)備掛在主控的 I2C控制器1 上,那么 adapter->nr = 1
dprintk("adapter->nr = %d I2C_device = 0x%x", adapter->nr, info->addr);
return -ENODEV;
}
static const struct i2c_device_id i2c_detect_id[] = {
{LMX_I2C_DETECT_DEVICE_NAME, 0},
{}
};
static struct i2c_driver i2c_detect_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.owner = THIS_MODULE,
.name = LMX_I2C_DETECT_DEVICE_NAME,
},
.detect = i2c_detect_Detect, // 會往所有的 I2C 控制器上尋指定的 I2C 設(shè)備地址的 I2C 設(shè)備,若有 ACK 回應(yīng)則會調(diào)用該函數(shù)
.id_table = i2c_detect_id,
.address_list = s_Normal_I2c, // 地址列表
};
/**************************** I2C 設(shè)備驅(qū)動框架 ****************************/
/* 重加載 */
static int I2c_Detect_Reload(void)
{
iprintk();
if(i2c_add_driver(&i2c_detect_driver)!= 0)
{
eprintk("i2c_add_driver() failed");
return -2;
}
i2c_del_driver(&i2c_detect_driver);
return 0;
}
static ssize_t I2c_Detect_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
{
unsigned long data = 0;
int ret;
strict_strtoul(buf, 16, &data);
iprintk("data = 0x%x", data);
s_Normal_I2c[0] = data;
I2c_Detect_Reload();
return count;
}
static ssize_t I2c_Detect_show(struct class *class, struct class_attribute *attr, char *buf)
{
return 1;
}
// 提供兩個接口函數(shù)給上層使用
static struct class_attribute I2c_Detect_class_attrs[] = {
__ATTR(i2c_addr, 0777, I2c_Detect_show, I2c_Detect_store),
__ATTR_NULL
};
static struct class I2c_Detect_class = {
.name = "zhc_i2c_detect",
.class_attrs = I2c_Detect_class_attrs,
};
static int __init i2c_detect_init(void)
{
int ret = 0;
dprintk();
// 創(chuàng)建設(shè)備節(jié)點(diǎn)
class_register(&I2c_Detect_class);
return ret;
}
static void __exit i2c_detect_exit(void)
{
dprintk();
class_unregister(&I2c_Detect_class);
}
module_init(i2c_detect_init);
module_exit(i2c_detect_exit);
MODULE_AUTHOR("lovemengx");
MODULE_DESCRIPTION("This I2C Devices Detect Driver Use Debug I2C devices");
MODULE_LICENSE("GPL");
|
|