在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
芯片精品文章合集(500篇!)    创芯人才网--重磅上线啦!
查看: 4243|回复: 3

[资料] I2C驱动分析

[复制链接]
发表于 2013-5-29 19:25:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
1. I2C 协议
    1.1  I2C总线工作原理
    I2C总线是由数据线SDA和时钟SCL构成的串行总线,各种被控制器件均并联在这条总线上,每个器件都有一个唯一的地址识别,可以作为总线上的一个发送器件或接收器件(具体由器件的功能决定)
    1.2  I2C总线的几种信号状态
    1.  空闲状态:SDA和SCL都为高电平。
    2.  开始条件(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
    3.  结束条件(P):SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。
    4.  数据有效:在SCL的高电平期间, SDA保持稳定,数据有效。SDA的改变只能发生在SCL的底电平期间。
    5.  ACK信号: 数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。
    1.3  I2C总线基本操作
    I2C总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL),同时控制总线的传输方向,并产生开始和停止条件。
    数据传输中,首先主器件产生开始条件,随后是器件的控制字节(前七位是从器件的地址,最后一位为读写位 )。接下来是读写操作的数据,以及 ACK响应信号。数据传输结束时,主器件产生停止条件
    2. Linux I2C 结构分析
    2.1 层次分析
    1. I2C Core
    I2C Core用于维护Linux的I2C核心部分,其中维护了两个静态的List,分别记录系统中的I2C driver结构和I2C adapter结构。
    static LIST_HEAD(adapters);
    static LIST_HEAD(drivers);
    I2C core提供接口函数,允许一个I2C adatper,I2C driver和I2C client初始化时在I2C core中进行注册,以及退出时进行注销。具体可以参见i2c_core.c代码。
    同时还提供了I2C总线读写访问的一般接口(具体的实现在与I2C控制器相关的I2C adapter中实现),主要应用在I2C设备驱动中。
    常用的主要是
    i2c_master_send()
    i2c_master_recv()
    i2c_transfer()
    2. I2C bus driver
    总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。但是总线驱动本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动调用其函数。
    在系统开机时,首先装载的是I2C总线驱动。一个总线驱动用于支持一条特定的I2C总线的读写。一个总线驱动通常需要两个模块,一个struct i2c_adapter和一个struct i2c_algorithm来描述:
    在 buses目录下的i2c-pxa.c中实现了PXA的I2C总线适配器,I2C adapter 构造一个对I2C core层接口的数据结构,并通过接口函数向I2C core注册一个控制器。I2C adapter主要实现对I2C总线访问的算法,iic_xfer() 函数就是I2C adapter底层对I2C总线读写方法的实现。同时I2C adpter 中还实现了对I2C控制器中断的处理函数。
    1) i2c-pxa.c定义了i2c_algorithm,并且实现了master的发送函数i2c_pxa_xfer(),以及设备查询总线的模式的函数i2c_pxa_functionality()
    static const struct i2c_algorithm i2c_pxa_algorithm = {
    .master_xfer = i2c_pxa_xfer,
    .functionality = i2c_pxa_functionality,
    };
    2) i2c-pxa.c中,实现了i2c_adapter,主要是在定义pxa-i2c时进行初始化,并且i2c_pxa_probe()中进行填充parent指针,并且调用
    ret = i2c_add_adapter(&i2c->adap);
    进行添加。
    static struct pxa_i2c i2c_pxa = {
    .lock = SPIN_LOCK_UNLOCKED,
    .adap = {
    .owner  = THIS_MODULE,
    .algo  = &i2c_pxa_algorithm,
    .name  = "pxa2xx-i2c.0",
    .retries = 5,
    },
    };
    总的来说,在i2c-pxa中,使用platform驱动模型,完成了i2c的总线两种模块struct i2c_adapter和struct i2c_algorithm
    3. I2C device driver
    I2C只有总线驱动是不够的,必须有设备才能工作。这就是I2C device driver的必要性。I2C的device是有两个模块来描述的,struct i2c_driver和struct i2c_client.
    在介绍chips目录下的device driver前有必要介绍一下i2c-dev.c文件。
    i2c-dev.c中提供了一个通用的I2C设备的驱动程序,实现了字符类型设备的访问接口,对设备的具体访问是通过I2C adapter来实现的。构造一个对I2C core层接口的数据结构,通过接口函数向 I2C Core注册一个I2C设备驱动。同时构造一个对用户层接口的数据结构,并通过接口函数向内核注册为一个主设备号为89的字符类型设备。
    static struct i2c_driver i2cdev_driver = {
    .driver = {
    .name = "dev_driver",
    },
    .id  = I2C_DRIVERID_I2CDEV,
    .attach_adapter = i2cdev_attach_adapter,
    .detach_adapter = i2cdev_detach_adapter,
    .detach_client = i2cdev_detach_client,
    };
    struct i2c_dev {
    struct list_head list;
    struct i2c_adapter *adap;
    struct device *dev;
    };
    该文件提供了用户层对I2C设备的访问,包括open,read,write,ioctl,release等常规文件操作,我们可以通过open函数打开 I2C的设备文件,通过ioctl函数设定要访问从设备的地址,然后就可以通过 read和write函数完成对I2C设备的读写操作。
    static const struct file_operations i2cdev_fops = {
    .owner  = THIS_MODULE,
    .llseek  = no_llseek,
    .read  = i2cdev_read,
    .write  = i2cdev_write,
    .ioctl  = i2cdev_ioctl,
    .open  = i2cdev_open,
    .release = i2cdev_release,
    };
    注:通过I2C driver提供的通用方法可以访问任何一个I2C的设备,但是其中实现的read,write及ioctl等功能完全是基于一般设备的实现,所有的操作数据都是基于字节流,没有明确的格式和意义。为了更方便和有效地使用I2C设备,我们可以为一个具体的I2C设备开发特定的I2C设备驱动程序,在驱动中完成对特定的数据格式的解释以及实现一些专用的功能。
    在chips目录下包含着各种device 的driver,完成各种从设备的注册。作为一般的I2C设备,使用i2c-dev.c里的操作足够完成操作了。
    当然如果不能完成,则需要独立完成该驱动,这就是chips目录下的代码。因为i2c-dev.c已经实现了I2C设备的文件操作接口,所以只要实现struct i2c_driver就可以了。对于某些特殊的操作,可以使用command接口进行控制。 当然,对于i2接口的fm芯片,则将struct i2c_driver放在i2c的chips目录下,而将另外fm操作相关的代码放在了/media/radio目录下了。在这个目录下需要完成读写接口的完成,这个大部分使用V4L2架构。
    i2c总线使用
    了解了i2c总线的主要结构成员及适配器、设备驱动的注册后,现在我们从上而下的来研究一下i2c总线的使用(仍然以i2c-dev.c为例):
    1、这是面向用户的虚拟字符设备所提供的所有i2c总线操作接口函数:
    static const struct file_operations i2cdev_fops = {
    .owner          = THIS_MODULE,
    .llseek         = no_llseek,
    .read           = i2cdev_read,
    .write          = i2cdev_write,
    .ioctl          = i2cdev_ioctl,
    .open           = i2cdev_open,
    .release        = i2cdev_release,
    };
    1)drivers/i2c/i2c-dev.c
    static int i2cdev_open(struct inode *inode, struct file *file)
    {
    unsigned int minor = iminor(inode);
    struct i2c_client *client;
    struct i2c_adapter *adap;
    struct i2c_dev *i2c_dev;
    i2c_dev = i2c_dev_get_by_minor(minor);    //通过设备文件的从设备号查找对应的i2c_dev
    if (!i2c_dev)
    return -ENODEV;
    adap = i2c_get_adapter(i2c_dev->adap->nr);    //查找对于的adap
    if (!adap)
    return -ENODEV;
    client = kzalloc(sizeof(*client), GFP_KERNEL);    //i2c从设备描述结构体
    if (!client) {
    i2c_put_adapter(adap);
    return -ENOMEM;
    }
    snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
    client->driver = &i2cdev_driver;
    /* registered with adapter, passed as client to user */
    client->adapter = adap;
    file->private_data = client;
    return 0;
    }
    注:
    i2cdev_open的主要作用是构建并初始化用于描述i2c从设备的结构体struct i2c_client.
    2)drivers/i2c/i2c-dev.c
    i2cdev_read
    -> i2c_master_recv
    -> i2c_transfer
    -> adap->algo->master_xfer(s3c24xx_i2c_xfer)
    3)drivers/i2c/i2c-dev.c
    i2cdev_write
    -> i2c_master_send
    -> i2c_transfer
    -> adap->algo->master_xfer(s3c24xx_i2c_xfer)
    7)drivers/i2c/busses/i2c-s3c2410.c
    s3c24xx_i2c_xfer
    -> s3c24xx_i2c_doxfer(wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5)) <----|
    -> s3c24xx_i2c_irq                                                               |
    -> i2s_s3c_irq_nextbyte                                                      |
    -> s3c24xx_i2c_stop                                                      |
    -> s3c24xx_i2c_master_complete(wake_up(&i2c->wait))------------------|
    更多资料可参考:http://emb.sunplusedu.com/
发表于 2013-7-22 18:46:20 | 显示全部楼层
感謝分享
发表于 2015-6-2 17:02:37 | 显示全部楼层
谢谢楼主
发表于 2018-8-26 18:02:11 | 显示全部楼层
Thanks for sharing
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-6-3 18:27 , Processed in 0.037236 second(s), 10 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表