搜索
热搜: ROHM 模拟 车载
查看: 2889|回复: 5

Linux驱动设备之I2C源码

  [复制链接]

该用户从未签到

89

主题

513

帖子

0

精华

金牌会员

最后登录
2022-3-30
发表于 2018-11-1 20:12:20 | 显示全部楼层 |阅读模式
Linux的I2C子系统分为三层,I2C核心层,I2C总线驱动层和I2C设备驱动层。I2C核心层由内核开发者提供,I2C总线驱动层有芯片厂商提供,而I2C设备驱动层由于设备的差异性,就只能是具体的开发需求具体实现了。而本实例是拿eeprom芯片AT24C02进行的具体分析。



I2C核心层管理所有关于I2C的数据结构,提供I2C总线驱动层和I2C设备驱动层的操作接口函数,I2C总线驱动层提供I2C核心层访问硬件设备的具体方法,I2C设备驱动层向I2C核心层添加新的数据(总线设备节点)并且提供用户层访问接口。

注意:I2C核心层其实已经提供了用户访问接口函数,每一个I2C总线对应一个设备,/dev/i2c-x(0,1,2...),一般不选择使用,而是自己编写特定的设备驱动



本文档只针对I2C设备驱动的编写方法进行描述,而I2C核心层实现可见driver/i2c/i2c-core.c中有具体实现,I2C总线驱动层具体平台具体分析,比如IMX6平台为drivers\i2c\busses/i2c-imx.c



下面开始正题:I2C设备驱动编写分两部分

第一、在平台文件board-mx6q_sabresd.c中添加i2c_board_info,以及将其注册到I2C核心层

第二、编写I2C设备驱动



1 在平台文件board-mx6q_sabresd.c中添加i2c_board_info,以及将其注册到I2C核心层

步骤:

a、初始化i2c_board_info 类型全局变量

//分配初始化i2c_board_info
static struct i2c_board_info at24c02[] = {
    {
        I2C_BOARD_INFO("at24c02", 0x50) //“at24c02“用来匹配
    }
};

b、在平台设备初始化函数(IMX6平台为mx6_sabresd_board_init)中注册i2c_board_info         

//注册AT24C02的硬件信息
        i2c_register_board_info(0,at24c02, ARRAY_SIZE(at24c02));//参数描述,第一个参数为busnum,第二个参数为struct i2c_board_info const *info,即挂接在总线上的设备集合数组,第三个参数,数组元素个数



2 编写I2C设备驱动

步骤:

a、初始化i2c_driver变量

static struct i2c_device_id at24c02_id[] = {
        {"at24c02", 0},
        //”at24c02“必须和i2c_board_info的type一致,匹配靠它进行
};

static struct i2c_driver at24c02_drv = {
    .driver = {
        .name = "tarena" //不重要,匹配不靠它
    },
    .probe = at24c02_probe, //匹配成功执行,i2c-core.c的probe函数会来回调这个函数执行
    .remove = at24c02_remove,
    .id_table = at24c02_id
};

b、注册i2c_driver变量

i2c_add_driver(&at24c02_drv);

c、在at24c02_probe函数中获取i2c_client变量,以及注册混杂设备,以用于后面的数据传输

static struct i2c_client *g_client;

static int at24c02_probe(
            struct i2c_client *client,
            struct i2c_device_id *id)
{
    //1.注册混杂设备驱动
    misc_register(&at24c02_dev);
    //2.记录匹配成功的i2c_client
    g_client = client;
    return 0; //成功返回0,失败返回负值
}

d、编写混杂设备操作函数

static struct miscdevice at24c02_dev = {
    .minor = MISC_DYNAMIC_MINOR, //自动分配次设备号
    .name = "at24c02", //dev/at24c02
    .fops = &at24c02_fops
};

static struct file_operations at24c02_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = at24c02_ioctl
};

e、实现at24c02_ioctl函数

ioctl函数实现数据传输接口,这里使用SMBUS接口将数据(地址,数据,设备地址(g_client->addr))丢给I2C总线驱动,启动I2C总线的硬件传输。

具体方法:

(1)打开SMBUS文档:内核源码\Documentation\i2c\smbus-protocol,找到对应的SMBUS接口函数

(2)打开芯片操作时序图,根据时序图找对应的SMBUS操作函数

(3)将addr,data和at24c02_probe函数中匹配成功的i2c_client通过对应的函数丢给I2C总线驱动然后启动I2C总线的硬件传输

比如AT24C02的读写函数分别为

i2c_smbus_read_byte_data(g_client, addr);

i2c_smbus_write_byte_data(g_client, addr, data);
回复

使用道具 举报

该用户从未签到

49

主题

2250

帖子

0

精华

论坛元老

最后登录
2020-12-15
发表于 2018-11-2 10:13:23 | 显示全部楼层
感谢分享               
回复 支持 反对

使用道具 举报

该用户从未签到

2384

主题

9836

帖子

0

精华

论坛元老

最后登录
2024-4-19
发表于 2019-3-3 14:20:28 | 显示全部楼层
学习学习Linux驱动设备之I2C源码
回复 支持 反对

使用道具 举报

该用户从未签到

0

主题

1

帖子

0

精华

新手上路

最后登录
2019-3-4
发表于 2019-3-4 11:08:35 | 显示全部楼层
马克一下
回复

使用道具 举报

该用户从未签到

0

主题

201

帖子

0

精华

高级会员

最后登录
2020-6-11
发表于 2019-3-27 11:13:07 | 显示全部楼层
感谢楼主的分享
回复 支持 反对

使用道具 举报

该用户从未签到

1347

主题

6657

帖子

0

精华

论坛元老

最后登录
2020-7-26
发表于 2020-5-29 19:21:06 | 显示全部楼层
超级实用学习学习了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|罗姆半导体技术社区

GMT+8, 2024-4-20 09:59 , Processed in 0.106294 second(s), 16 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表