iic-调试笔记

内核源码  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设备:i2c_transter()或SMBus         (SMBus在linux/Document/i2c/instantialing-device中有介绍)
如下写函数
static ssize_t at24cxx_read(struct file *file, char __user *buf, size_t size, loff_t * offset)
{
unsigned char address;
unsigned char data;
struct i2c_msg msg[2];
int ret;

/* address = buf[0] 
* data    = buf[1]
*/
if (size != 1)
return -EINVAL;

copy_from_user(&address, buf, 1);


/* 数据传输三要素: 源,目的,长度 */


/* 读AT24CXX时,要先把要读的存储空间的地址发给它 */
msg[0].addr  = at24cxx_client->addr;  /* 目的 */
msg[0].buf   = &address;              /* 源 */
msg[0].len   = 1;                     /* 地址=1 byte */
msg[0].flags = 0;                     /* 表示写 */


/* 然后启动读操作 */
msg[1].addr  = at24cxx_client->addr;  /* 源 */
msg[1].buf   = &data;                 /* 目的 */
msg[1].len   = 1;                     /* 数据=1 byte */
msg[1].flags = I2C_M_RD;                     /* 表示读 */




ret = i2c_transfer(at24cxx_client->adapter, msg, 2);
if (ret == 2)
{
copy_to_user(buf, &data, 1);
return 1;
}
else
return -EIO;
}
SMBus之支持i2c协议的一部分:它包括如下函数,每个函数都有不同的发送顺序
i2c_smbus_write_byte_date()               发送顺序:S ADDR W/R  A COMM A DATA NA P
i2c_smbus_read_byte_date()               发送顺序:S ADDR  W A S ADDR R DATA NA P
等等

*****************************************************************


不自己写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结构体

i2c_new_device   直接在init函数中调用次函数








核心层提供的统一的操作函数来读写i2c设备:i2c_transter()和或SMBus         (SMBus在linux/Document/i2c/instantialing-device中有介绍)
如下写函数
static ssize_t at24cxx_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
unsigned char val[2];
struct i2c_msg msg[1];
int ret;

/* address = buf[0] 
 * data    = buf[1]
 */
if (size != 2)
return -EINVAL;

copy_from_user(val, buf, 2);


/* 数据传输三要素: 源,目的,长度 */
msg[0].addr  = at24cxx_client->addr;  /* 目的 */
msg[0].buf   = val;                   /* 源 */
msg[0].len   = 2;                     /* 地址+数据=2 byte */
msg[0].flags = 0;                     /* 表示写 */


ret = i2c_transfer(at24cxx_client->adapter, msg, 1);
if (ret == 1)
return 2;
else
return -EIO;
}
SMBus之支持i2c协议的一部分:它包括如下函数,每个函数都有不同的发送顺序
i2c_smbus_write_byte_date()               发送顺序:S ADDR W/R  A COMM A DATA NA P
i2c_smbus_read_byte_date()               发送顺序:S ADDR  W A S ADDR R DATA NA P
等等

你可能感兴趣的:(iic-调试笔记)