先用韦老师的图:

注:  新版本内核的i2c驱动框架采用了    i2c_client -------> i2c_bus_type  <-------- i2c_driver   框架


如何构建i2c_client的4种方法 1.
定义一个 i2c_board_info,用 i2c_register_board_info 注册,再生成i2c_client
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; // dts中匹配的设备节点
               struct fwnode_handle *fwnode;
              int irq;
              }; i2c_register_board_info(busnum, //使用哪个总线
           i2c_board_info , // i2c_board_info 中的哪个 I2C_BOARD_INFO
           len) // i2c_board_info 中有多少 I2C_BOARD_INFO
              把它们放入__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
2,用 i2c_new_device 或 i2c_new_probed_device 直接注册i2c_client
                  static struct i2c_board_info at24cxx_info = {    I2C_BOARD_INFO("at24c08", 0x50),   };    // 地址信息 + 名字信息
  , struct i2c_client * // 如果匹配 ,返回一个生成的i2c_client
     i2c_new_device( i2c_adapter // 确定i2c设备存在,直接创建
     i2c_board_info ): // 定义好的板载i2c设备的名字,地址       short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END }; // 地址信息
       static struct i2c_board_info at24cxx_info = { I2C_BOARD_INFO("at24c08"), }; // 名字信息
   , struct i2c_client * // 如果有匹配的地址列表 ,返回一个生成的i2c_client
  i2c_new_probed_device(i2c_adapter ,
  i2c_board_info , // 定义好的板载i2c设备的名字
  addr_list, // 所有的支持的i2c设备地址
  int (*probe)(struct i2c_adapter *, unsigned short addr)):对于"已经识别出来的设备"(probed_device),才会创建("new")    调用传递参数的probe---> probe(adap, addr_list[i]) // 确定设备是否真实存在
   info->addr = addr_list[i];
  i2c_new_device(adap, info);
  at24xx_dev.c源码
static struct i2c_board_info at24cxx_info = {
I2C_BOARD_INFO("at24c08", 0x50),
}; static struct i2c_client *at24cxx_client; static int at24cxx_dev_init(void)
{
struct i2c_adapter *i2c_adap; i2c_adap = i2c_get_adapter();
at24cxx_client = i2c_new_device(i2c_adap, &at24cxx_info);
i2c_put_adapter(i2c_adap); return ;
} static void at24cxx_dev_exit(void)
{
i2c_unregister_device(at24cxx_client);
} module_init(at24cxx_dev_init);
module_exit(at24cxx_dev_exit);
MODULE_LICENSE("GPL");
static struct i2c_client *at24cxx_client;

static const unsigned short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END };

static int at24cxx_dev_init(void)
{
struct i2c_adapter *i2c_adap;
struct i2c_board_info at24cxx_info; memset(&at24cxx_info, , sizeof(struct i2c_board_info));
strlcpy(at24cxx_info.type, "at24c08", I2C_NAME_SIZE); i2c_adap = i2c_get_adapter();
at24cxx_client = i2c_new_probed_device(i2c_adap, &at24cxx_info, addr_list, NULL);
i2c_put_adapter(i2c_adap); if (at24cxx_client)
return ;
else
return -ENODEV;
} static void at24cxx_dev_exit(void)
{
i2c_unregister_device(at24cxx_client);
} module_init(at24cxx_dev_init);
module_exit(at24cxx_dev_exit);
MODULE_LICENSE("GPL");


 3, 从用户空间创建设备i2c_client
            创建设备
    echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-/new_device
    导致i2c_new_device被调用      删除设备
    echo 0x50 > /sys/class/i2c-adapter/i2c-/delete_device
    导致i2c_unregister_device


4.用i2c_deriver->detect函数,探测生成i2c_client
         前面的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,
.detect = at24cxx_detect, /* 用这个函数来检测设备确实存在 */
.address_list = addr_list, /* 这些设备的地址 */
}; 去"class表示的这一类"I2C适配器,用"detect函数"来确定能否找到"address_list里的设备",
如果能找到就调用i2c_new_device来注册i2c_client, 这会和i2c_driver的id_table比较,如果匹配,调用probe

at24cxx_drv.c源码:

static int __devinit at24cxx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return ;
} static int __devexit at24cxx_remove(struct i2c_client *client)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return ;
} static const struct i2c_device_id at24cxx_id_table[] = {
{ "at24c08", },
{}
}; static int at24cxx_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
/* 能运行到这里, 表示该addr的设备是存在的
* 但是有些设备单凭地址无法分辨(A芯片的地址是0x50, B芯片的地址也是0x50)
* 还需要进一步读写I2C设备来分辨是哪款芯片
* detect就是用来进一步分辨这个芯片是哪一款,并且设置info->type
*/ printk("at24cxx_detect : addr = 0x%x\n", client->addr); /* 进一步判断是哪一款 */ strlcpy(info->type, "at24c08", I2C_NAME_SIZE);
return ;
} static const unsigned short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END }; /* 1. 分配/设置i2c_driver */
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,
.detect = at24cxx_detect, /* 用这个函数来检测设备确实存在 */
.address_list = addr_list, /* 这些设备的地址 */
}; static int at24cxx_drv_init(void)
{
/* 2. 注册i2c_driver */
i2c_add_driver(&at24cxx_driver); return ;
} static void at24cxx_drv_exit(void)
{
i2c_del_driver(&at24cxx_driver);
} module_init(at24cxx_drv_init);
module_exit(at24cxx_drv_exit);
MODULE_LICENSE("GPL");

注册i2c_driver内部流程

i2c_add_driver
i2c_register_driver
a. at24cxx_driver放入i2c_bus_type的drv链表
并且从dev链表里取出i2c_client,用i2c_driver->id_table->{"at24c08"}与i2c_client->name比较,
       成功则调用i2c_client->probe函数
       在probe函数中创建字符设备节点
  i2c_client->name 来自 i2c_board_info->I2C_BOARD_INFO("at24c08", 0x50) 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 = ; address_list[i] != I2C_CLIENT_END; i += ) {
err = i2c_detect_address(temp_client, driver);
/* 判断这个设备是否存在:简单的发出S信号确定有ACK */
if (!i2c_default_probe(adapter, addr))
return ; memset(&info, , sizeof(struct i2c_board_info));
info.addr = addr; // 设置info.type
err = driver->detect(temp_client, &info); i2c_new_device
如何创建注册i2c_adapter
static int s3c2440_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
} static u32 s3c2440_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
} static const struct i2c_algorithm s3c2440_i2c_algo = {
// .smbus_xfer = ,
.master_xfer = s3c2440_i2c_xfer,
.functionality = s3c2440_i2c_func,
}; /* 1. 分配/设置i2c_adapter
*/
static struct i2c_adapter s3c2440_i2c_adapter = {
.name = "s3c2440_100ask",
.algo = &s3c2440_i2c_algo,
.owner = THIS_MODULE,
}; static int i2c_bus_s3c2440_init(void)
{
/* 2. 注册i2c_adapter */ i2c_add_adapter(&s3c2440_i2c_adapter); return ;
} static void i2c_bus_s3c2440_exit(void)
{
i2c_del_adapter(&s3c2440_i2c_adapter);
} module_init(i2c_bus_s3c2440_init);
module_exit(i2c_bus_s3c2440_init);
MODULE_LICENSE("GPL");

如何创建i2c_driver

static int __devinit at24cxx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return ;
} static int __devexit at24cxx_remove(struct i2c_client *client)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return ;
} static const struct i2c_device_id at24cxx_id_table[] = {
{ "at24c08", },
{}
}; /* 1. 分配/设置i2c_driver */
static struct i2c_driver at24cxx_driver = {
.driver = {
.name = "100ask",
.owner = THIS_MODULE,
},
.probe = at24cxx_probe,
.remove = __devexit_p(at24cxx_remove),
.id_table = at24cxx_id_table,
}; static int at24cxx_drv_init(void)
{
/* 2. 注册i2c_driver */
i2c_add_driver(&at24cxx_driver); return ;
} static void at24cxx_drv_exit(void)
{
i2c_del_driver(&at24cxx_driver);
} module_init(at24cxx_drv_init);
module_exit(at24cxx_drv_exit);
MODULE_LICENSE("GPL");

I2C驱动框架 (kernel-3.4.2)的更多相关文章

  1. I2C驱动框架(四)

    参考:I2C子系统之platform_driver初始化——I2C_adap_s3c_init() 在完成platform_device的添加之后,i2c子系统将进行platform_driver的注 ...

  2. I2C驱动框架(三)

    参考:I2C子系统之platform_device初始化——smdk2440_machine_init() I2C驱动框架还应用了另一种总线-设备-驱动模型,平台设备总线platform_bus_ty ...

  3. I2C驱动框架(kernel-2.6.22.6)

    以用i2c通信的实时时钟为例 框架入口源文件:i2c_m41t11.c (可根据入口源文件,再按着框架到内核走一遍) 内核版本:linux_2.6.22.6   硬件平台:JZ2440 以下是驱动框架 ...

  4. Linux 驱动框架---i2c驱动框架

    i2c驱动在Linux通过一个周的学习后发现i2c总线的驱动框架还是和Linux整体的驱动框架是相同的,思想并不特殊比较复杂的内容如i2c核心的内容都是内核驱动框架实现完成的,今天我们暂时只分析驱动开 ...

  5. 【Linux高级驱动】I2C驱动框架分析

    1.i2c-dev.c(i2c设备驱动组件层) 功能:1)给用户提供接口 i2c_dev_init  //入口函数 /*申请主设备号*/ register_chrdev(I2C_MAJOR(), &q ...

  6. I2C驱动框架(二)

    参考:I2C子系统之I2C bus初始化——I2C_init() 在linux内核启动的时候最先执行的和I2C子系统相关的函数应该是driver/i2c/i2c-core.c文件中的i2c_init( ...

  7. Linux I2C驱动框架

    Linux的I2C体系结构分为3个组成部分: I2C核心(  i2c-core.c ): I2C核心提供了I2C总线驱动和设备驱动的注册.注销方法.I2C通信方法("algorithm&qu ...

  8. I2C驱动框架(五)

    参考:I2C子系统之 adapter driver注册——I2C_dev_init() i2c的操作在内核中是当做字符设备来操作的,相关初始化在由i2c_dev_init函数来初始化. static ...

  9. I2C驱动框架(一)

    参考:I2C子系统之内核中I2C子系统的结构 结合vmlinux.lds和Makefile可确定i2c初始化函数的执行顺序如下: 1./dricer/i2c/i2c-core.c中的函数:i2c_in ...

随机推荐

  1. MATLAB基础函数命令

    1. 常用命令 dir:列出当前目录下的所有文件 clc:清除命令窗 clear all:清除环境(从内存中清除所有变量) who:将内存中的当前变量以简单形式列出 close all: 关闭所有的 ...

  2. Servlet 2.0 && Servlet 3.0 新特性

    概念:透传. Callback 在异步线程中是如何使用的.?? Servlet 2.0 && Servlet 3.0 新特性 Servlet 2.0 && Servle ...

  3. hdoj:2085

    核反应堆 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  4. Android开发怎么让自己的APP UI漂亮、大方(规范篇一)

    首先,笔者是站立在开发者的角度来看UI设计的,欢迎专业人士提供指导,不多说,来看怎么把UI设计和开发高效结合起来~ 一.约定APP开发中的一些规则 1.大部分图标满足HDPI(高清)即可,比如:大众点 ...

  5. JAVA并发编程——守护线程(Daemon Thread)

    在Java中有两类线程:用户线程 (User Thread).守护线程 (Daemon Thread). 所谓守护 线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称 ...

  6. 第四百零五节,centos7下搭建sentry错误日志服务器,接收python以及Django错误,

    第四百零五节,centos7下搭建sentry错误日志服务器,接收python以及Django错误, 注意:版本,不然会报错 Docker >=1.11Compose >1.6.0 通过d ...

  7. windows ngix 安装 配置 使用

    参考版本nginx-1.10.3 一.常用命令 start nginx.exe                      //开启服务 nginx.exe -s stop                ...

  8. NuGet Packages are missing,This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.

    错误内容 This project references NuGet package(s) that are missing on this computer. Use NuGet Package R ...

  9. scala 隐式详解(implicit关键字)

    掌握implicit的用法是阅读spark源码的基础,也是学习scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把 ...

  10. Codeforces Round 504

    (交互题真神奇,,,我自己瞎写了一发目测样例都没过去就AC了...) (只出了两题的竟然没掉下蓝名真是可怕) A:我的代码太不美观了,放个同学的(因为我是c++63分的蒟蒻所以根本不知道那些函数怎么用 ...