内核源码 linux/Document/i2c/instantialing-device文档,讲了iic设备的构建方法
a. 设备的4种构建方法
a.1 定义一个i2c_board_info, 里面有:名字, 设备地址
然后i2c_register_board_info(busnum, ...) (把它们放入__i2c_board_list链表)
list_add_tail(&devinfo->list, &__i2c_board_list);
链表何时使用:
i2c_register_adapter > i2c_scan_static_board_info > i2c_new_device
使用限制:必须在 i2c_register_adapter 之前 i2c_register_board_info
所以:不适合我们动态加载insmod
i2c_new_device 直接在init函数中调用次函数 //对应i2c_unregister_dev
: 认为设备肯定存在,不论你的id_table中的addr是否存在它都会调用probe
i2c_new_probed_device//先检测设备地址是否有对应设备,如果有对应设备才i2c_new_device
probe(adap, addr_list[i]) /* 根据地址链表,确定设备是否真实存在 */找到设备驱动模型另一边的项后调用probe
info->addr = addr_list[i];
i2c_new_device(adap, info);
i2c_new_device //在设备驱动模型中与i2c_add_driver对应,以上有i2c_add_driver的解释
a.3 从用户空间创建设备
创建设备
echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-0/new_device //在内核里边搜索new_device 会发现在i2c_core.c中 DEVICE_ATTR(new_device,** ,func)
在func中会调用i2c_new_device被调用
导致i2c_new_device被调用
删除设备
echo 0x50 > /sys/class/i2c-adapter/i2c-0/delete_device
导致i2c_unregister_device
a.4 前面的3种方法都要事先确定适配器(I2C总线,I2C控制器)
如果我事先并不知道这个I2C设备在哪个适配器上,怎么办?去class表示的所有的适配器上查找
有上一些I2C设备的地址是一样,怎么继续分配它是哪一款?用detect函数
static struct i2c_driver at24cxx_driver = {
.class = I2C_CLASS_HWMON, /* 表示去哪些适配器上找设备 */
.driver = {
.name = "100ask",
.owner = THIS_MODULE,
},
.probe = at24cxx_probe,
.remove = __devexit_p(at24cxx_remove),
.id_table = at24cxx_id_table, //里边的name选项很重要 必须与device相对应匹配
.detect = at24cxx_detect, /* 用这个函数来检测设备确实存在 */
.address_list = addr_list, /* 这些设备的地址 */
.attach_adapter, //address_list中有几个地址,attach_adapter就会被调用几次,此函数的作用是如果设备地址相同,进一步分辨设备时调用
};
去"class表示的这一类"I2C适配器,用"detect函数"来确定能否找到"address_list里的设备",
如果能找到就调用i2c_new_device来注册i2c_client, 这会和i2c_driver的id_table比较,
如果匹配,调用probe
i2c_add_driver //在设备驱动模型中与i2c_new_device对应,以上有i2c_new_device的解释
i2c_register_driver
a. at24cxx_driver放入i2c_bus_type的drv链表
并且从dev链表里取出能匹配的i2c_client并调用probe
driver_register
b. 对于每一个适配器,调用__process_new_driver
对于每一个适配器,调用它的函数确定address_list里的设备是否存在
如果存在,再调用detect进一步确定、设置,然后i2c_new_device
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver);
__process_new_driver
i2c_do_add_adapter
/* Detect supported devices on that bus, and instantiate them */
i2c_detect(adap, driver);
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
err = i2c_detect_address(temp_client, driver);
/* 判断这个设备是否存在:简单的发出S信号确定有ACK */
if (!i2c_default_probe(adapter, addr))
return 0;
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = addr;
// 设置info.type
err = driver->detect(temp_client, &info);
*****************************************************************
不自己写i2c驱动程序,使用内核的万能驱动程序 //有人已经将SMBus风装起来了,我们可以直接用 //在dev-interface文档中有介绍
文档中有介绍:已经有人封装的库名字为i2c-tool ,可以去百度一下 就会搜索到其源码
iic的协议就不做记录了,这个太简单了
总线 设备 驱动
struct i2c_bus_type{ //总线结构体
.match //用来匹配设备与驱动
.id_table //match用我来匹配 {.name .addr等}
}
struct i2c_client{
}
struct i2c_driver{
}
i2c_add_driver
i2c的好多函数会用到adapter 每个adapter对应一个iic控制后,一些设备会有几个iic接口
i2c_get_adapter(0) //获得第0个iic控制借口
I2C_put_adapter(0)
还会用到的参数是i2c_board结构体