i2c驱动程序.docx

上传人:b****1 文档编号:12786259 上传时间:2023-04-22 格式:DOCX 页数:117 大小:64.05KB
下载 相关 举报
i2c驱动程序.docx_第1页
第1页 / 共117页
i2c驱动程序.docx_第2页
第2页 / 共117页
i2c驱动程序.docx_第3页
第3页 / 共117页
i2c驱动程序.docx_第4页
第4页 / 共117页
i2c驱动程序.docx_第5页
第5页 / 共117页
点击查看更多>>
下载资源
资源描述

i2c驱动程序.docx

《i2c驱动程序.docx》由会员分享,可在线阅读,更多相关《i2c驱动程序.docx(117页珍藏版)》请在冰豆网上搜索。

i2c驱动程序.docx

i2c驱动程序

目录

1IIC子系统初始化1

1.1IIC子系统初始化i2c_init1

1.2IIC子系统退出函数i2c_exit1

2i2c_bus_type总线2

2.1总线的match方法2

2.2总线的probe方法2

2.3一些函数3

2.3.1i2c_match_id()函数3

3i2c_driver驱动3

3.1i2c_driver注册4

3.1.1i2c_add_driver添加一个驱动4

3.1.2i2c_register_driver注册一个驱动4

3.2驱动注册中重要函数5

4适配器adapter驱动程序5

4.1i2c_adapter适配器5

4.1.1IIC适配器加载函数6

4.1.3i2c_register_adapter()适配器注册函数8

4.1.4适配器卸载函数i2c_del_adapter()9

4.2s3c24xx_i2c适配器(板子具体扩充)13

4.3适配器通信方法14

4.3.1i2c_msg结构和i2c_transfer14

4.3.1.1i2c_transfer15

4.3.2i2c_algorithm结构16

4.3.3s3c24xx_i2c_algorithm结构体(板子具体扩展)16

4.3.4s3c24xx_i2c_irq中断函数19

4.3.5一些其它通讯函数23

5IIC设备层驱动程序24

5.1IIC设备驱动模块加载和卸载24

5.2platform_device设备24

5.2.1s3c2410_platform_i2c25

5.2.2s3c_i2c0_set_platdata25

5.3.3default_i2c_data026

5.3platform_driver驱动26

5.3.1probe函数26

5.3.2remove函数29

5.4一些函数29

6i2c_client31

6.1i2c_client_type32

6.2生成i2c_clent33

6.2.1i2c_detect根据驱动上的所有地址数据产生所有的i2c设备33

6.2.2i2c_detect_address根据client和driver产生一个i2c设备35

6.2.3i2c_new_device实例化一个i2c设备36

6.2.4adapter注册时37

6.2.5i2c_driver注册时38

6.3其它函数39

6.3.1i2c_smbus_xfer39

6.3.2i2c_smbus_xfer_emulated39

6.4.i2c_board_info43

7i2c-dev.c设备驱动45

7.1i2c_dev_init45

7.2i2c_dev设备46

7.3新增的i2c_driver驱动---i2cdev_driver46

7.3.1i2cdev_attach_adapter获得一个i2c_dev并注册添加属性46

7.3.2i2cdev_detach_adapter函数47

7.3.3属性dev_attr_name47

7.4文件操作48

7.4.1open函数48

7.4.2read函数49

7.4.3write函数50

7.4.4unlocked_ioctl函数--i2cdev_ioctl51

7.5一些函数54

7.5.1get_free_i2c_dev获得一个新的i2c_dev结构并加入i2c_dev_list链表54

7.5.2i2c_dev_get_by_minor遍历i2c_dev_list链表查找此设备号为index的i2c_dev54

7.5.3i2c_get_adapter和i2c_put_adapter55

7.5.4i2c_new_dummy55

8at24驱动—非系统55

8.1模块初始化55

8.2数据结构56

8.2.1at24_data56

8.2.2at24_ids56

8.3at24驱动模块at24_driver57

8.3.1驱动的probe函数57

8.3.2驱动的remove函数60

8.3.3at24_bin_read函数60

8.3.4at24_bin_write函数62

8.4一些函数64

8.4.1at24_translate_offset64

1IIC子系统初始化

1.1IIC子系统初始化i2c_init

staticint__initi2c_init(void)

{

intretval;

retval=bus_register(&i2c_bus_type);//注册IIC总线i2c_bus_type

if(retval)

returnretval;

#ifdefCONFIG_I2C_COMPAT

i2c_adapter_compat_class=class_compat_register("i2c-adapter");

if(!

i2c_adapter_compat_class){

retval=-ENOMEM;

gotobus_err;

}

#endif

retval=i2c_add_driver(&dummy_driver);

//调用i2c_register_driver(THIS_MODULE,driver),这个dummy_driver是个空驱动

if(retval)

gotoclass_err;

return0;

class_err:

#ifdefCONFIG_I2C_COMPAT

class_compat_unregister(i2c_adapter_compat_class);

bus_err:

#endif

bus_unregister(&i2c_bus_type);

returnretval;

}

1.2IIC子系统退出函数i2c_exit

staticvoid__exiti2c_exit(void)

{

i2c_del_driver(&dummy_driver);//注销IIC设备驱动程序

#ifdefCONFIG_I2C_COMPAT

class_compat_unregister(i2c_adapter_compat_class);

#endif

bus_unregister(&i2c_bus_type);//注销IIC总线i2c_bus_type

}

postcore_initcall(i2c_init);

module_exit(i2c_exit);

2i2c_bus_type总线

structbus_typei2c_bus_type={

.name="i2c",

.match=i2c_device_match,

.probe=i2c_device_probe,

.remove=i2c_device_remove,

.shutdown=i2c_device_shutdown,

.suspend=i2c_device_suspend,

.resume=i2c_device_resume,

};

2.1总线的match方法

staticinti2c_device_match(structdevice*dev,structdevice_driver*drv)

{

structi2c_client*client=i2c_verify_client(dev);//设备的类型必须是i2c_client_type才能正常获得client

//而只有client的device_type是i2c_client_type,adapter的不是i2c_client_type型的。

从而若dev是adapter中的dev的话是不会再往下走,直接返回0

structi2c_driver*driver;

if(!

client)

return0;

driver=to_i2c_driver(drv);

/*matchonanidtableifthereisone*/

if(driver->id_table)

returni2c_match_id(driver->id_table,client)!

=NULL;//驱动的id和设备的名字是否匹配,匹配返回1

return0;

}//match成功后系统就把dev的driver设成driver了

staticconststructi2c_device_id*i2c_match_id(conststructi2c_device_id*id,conststructi2c_client*client)

{

while(id->name[0]){

if(strcmp(client->name,id->name)==0)

returnid;

id++;

}

returnNULL;

}

总的来说是i2c_driver驱动的id_table的名字和i2c_client设备的名字匹配。

不管adapter设备。

match后系统把i2c_client->dev的driver设成是此i2c_driver->driver。

2.2总线的probe方法

实际调研i2c_driver的probe函数,由于match方法只有是i2c_client_type类型才能匹配,然后才能调用probe,所以此处的dev也只有是client类型才行。

staticinti2c_device_probe(structdevice*dev)

{

structi2c_client*client=i2c_verify_client(dev);

structi2c_driver*driver;

intstatus;

if(!

client)

return0;

driver=to_i2c_driver(dev->driver);

if(!

driver->probe||!

driver->id_table)

return-ENODEV;

client->driver=driver;//系统只设置了系统的设备和驱动的关系,自己的关系自己设置

if(!

device_can_wakeup(&client->dev))

device_init_wakeup(&client->dev,client->flags&I2C_CLIENT_WAKE);

dev_dbg(dev,"probe\n");

//比较i2c_driver的id_table和i2c_client名字是否匹配

status=driver->probe(client,i2c_match_id(driver->id_table,client));

if(status)

client->driver=NULL;

returnstatus;

}

2.3一些函数

2.3.1i2c_match_id()函数

i2c_match_id比较id和i2c_client名字是否匹配

staticconststructi2c_device_id*i2c_match_id(conststructi2c_device_id*id,conststructi2c_client*client)

{

while(id->name[0]){

if(strcmp(client->name,id->name)==0)

returnid;

id++;

}

returnNULL;

}

3i2c_driver驱动

structi2c_driver{

unsignedintclass;//驱动的类型

//注意出现一个新总线或移除一个新总线时的驱动。

应该尽量避免使用这个,可能未来会取消

int(*attach_adapter)(structi2c_adapter*);//检测到适配器时调用(传统驱动),感觉i2c_detect调用后调用attach_adapter函数,或是i2c_new_device后调用的

int(*detach_adapter)(structi2c_adapter*);//卸载适配器时调用(传统驱动)

//标准驱动模型接口,支持动态插入,要么只定义下面的的新类型的设备驱动函数,要么之定义上面两个不可以动态插入和拔出的旧的函数。

int(*probe)(structi2c_client*,conststructi2c_device_id*);//新类型设备的探测函数

int(*remove)(structi2c_client*);//新类型设备的移除函数

void(*shutdown)(structi2c_client*);//关闭设备

int(*suspend)(structi2c_client*,pm_message_tmesg);//挂起设备

int(*resume)(structi2c_client*);//恢复设备

//使用命令是设备完成特殊的功能,类似ioctl函数

int(*command)(structi2c_client*client,unsignedintcmd,void*arg);

structdevice_driverdriver;//设备驱动结构体

conststructi2c_device_id*id_table;//设备ID表

//自动设备创建调用用的设备检测回调函数

int(*detect)(structi2c_client*,intkind,structi2c_board_info*);//自动探测设备的回调函数

conststructi2c_client_address_data*address_data;//设备所在的地址范围

structlist_headclients;//指向驱动支持的设备

};

其中设备ID数据结构为:

structi2c_device_id{

charname[I2C_NAME_SIZE];

kernel_ulong_tdriver_data/*Dataprivatetothedriver*/

__attribute__((aligned(sizeof(kernel_ulong_t))));

};

structi2c_driver–代表一个I2C设备驱动,对应一套驱动方法,一个i2c_driver上可以支持多个同等类型的i2c_client。

driver.owner应该设定为模块拥有者。

driver.name应该设定为驱动的名字。

对于自动设备检测,必须定义detect和address_data。

应该设置class,否则只会创建强制设定了模块参数的设备。

detect函数至少应该填充i2c_board_info的name字段,成功检测后处理,可能也会处理flags字段。

若没有detect,则针对列举的设备驱动仍会正常运行。

不会支持检测到的设备。

传递给detect的i2c_client结构不是一个真正的i2c_client。

它只被粗略初始化使得可以调用i2c_smbus_read_byte_data和friends。

不要用它做任何事情。

通常,不允许调用dev_dbg和它的friends。

3.1i2c_driver注册

3.1.1i2c_add_driver添加一个驱动

使用i2c_add_driver函数注册一个驱动。

staticinlineinti2c_add_driver(structi2c_driver*driver)

{

returni2c_register_driver(THIS_MODULE,driver);

}

3.1.2i2c_register_driver注册一个驱动

1.注册i2c_driver中的driver,会调用总线的probe和match方法,只匹配和探测client设备。

2.初始化驱动支持的设备链表

3.对于drv的总线上的所有设备运行__attach_adapter,对于drv的总线上的所有adapter设备根据此驱动上的所有地址数据产生adapter所有的i2c设备;并调用driver的attach_adapter函数。

staticstructi2c_driverdummy_driver={

.driver.name="dummy",

.probe=dummy_probe,

.remove=dummy_remove,

.id_table=dummy_id,

};

inti2c_register_driver(structmodule*owner,structi2c_driver*driver)

{

intres;

if(unlikely(WARN_ON(!

i2c_bus_type.p)))//总线已经注册过的话则已经定义了私有数据

return-EAGAIN;

driver->driver.owner=owner;

driver->driver.bus=&i2c_bus_type;

//注册返回时,驱动核心已经调用probe匹配未绑定设备

//driver_register会对于总线的所有设备(进入match和probe后发现这里的设备只是client设备)调用match和probe

//(因为i2c_driver->driver的match和probe没有定义,所以调用总线的match和Probe,而总线的probe调用了i2c_driver的probe函数)

//只初始化了owner和bus没有初始化driver中别的函数。

res=driver_register(&driver->driver);

if(res)

returnres;

pr_debug("i2c-core:

driver[%s]registered\n",driver->driver.name);

INIT_LIST_HEAD(&driver->clients);//初始化驱动支持的设备链表

/*Walktheadaptersthatarealreadypresent*/

mutex_lock(&core_lock);

bus_for_each_dev(&i2c_bus_type,NULL,driver,__attach_adapter);

//对于drv的总线上的所有设备(进入函数里会发现是所有adpter设备)运行__attach_adapter,也就是针对所有总线上的所有adapter设备执行i2c_driver的attach函数,产生对应的i2c_client设备。

mutex_unlock(&core_lock);

return0;

}

3.2驱动注册中重要函数

4适配器adapter驱动程序

4.1i2c_adapter适配器

structi2c_adapter{

structmodule*owner;//THIS_MODULE

unsignedintid;//定义于i2c_id.h中

unsignedintclass;/*允许探测的驱动类型*/

conststructi2c_algorithm*algo;/*指向适配器的驱动程序*/

void*algo_data;//指向适配器的私有数据,根据不同情况使用的方法不同

/*datafieldsthatarevalidforalldevices*/

u8level;/*nestinglevelforlockdep*/

structmutexbus_lock;//获得总线的锁

inttimeout;/*injiffies超时*/

intretries;//重试次数

structdevicedev;/*指向适配器设备结构体*/

//adapter的子设备应该是client中的dev

//device_for_each_child(&adapter->dev,&addr,__i2c_check_addr);

//之后__i2c_check_addr函数中可以i2c_verify_client();获得子设备对应的client。

intnr;//好像是iic控制器数量,也用于次设备号

charname[48];//适配器名称

structcompletiondev_released;//用于同步的完成量

};

i2c_adapter用来辨识一个物理i2c总线控制器,带有必要的访问算法。

相当于一个IIC总线的控制器。

系统中可以有多个总线适配器。

I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。

i2c_adapter通过device结构连接到i2c总线上,aglo指针指向具体的总线通信方法s3c24xx_i2c_algorithm结构体。

4.1.1IIC适配器加载函数

4.1.1.1i2c_add_adapter()函数

当驱动开发人员拿到一块新的电路板,并研究了响应的IIC适配器后,就应该使用内核提供的框架函数向IIC子系统中添加一个新的适配器。

这个过程如下所示。

声明一个i2cadapter,使用动态busnumber。

此时busnumber不重要。

例如,USB链接或PCI插卡动态增加的I2C适配器。

返回0,则分配了新的busnumber(实际上分配了一个新的ID号)并存贮到adap->nr,并使制定的adapter对于client来说生效了否则返回负的errno(ENOMEM/EAGAIN)。

inti2c_add_adapter(structi2c_adapter*adapter)

{

intid,res=0;

retry:

if(idr_pre_get(&i2c_adapter_idr,GFP_KERNEL)==0)//为ID号分配内存

return-ENOMEM;

mutex_lock(&core_lock);

res=idr_get_new_above(&i2c_adapter_idr,adapter,__i2c_first_dynamic_bus_num,&id);

//使ID号id与指针adapter关联,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 外语学习 > 英语考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1