Linux I2C设备驱动编写 - 图文(5)

2019-04-15 23:11

if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); //如果adapter的总线号小于动态分配的总线号的最小那个,说明是板级adapter。 //因为通过i2c_add_adapter加入的适配器所分配的总线号一定是比__i2c_first_dynamic_bus_num大的。 ... } 对于i2c_add_numbered_adapter来说会触发i2c_scan_static_board_info:

static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; down_read(&__i2c_board_lock); //持有读写锁的读,有用户读的时候不允许写入 list_for_each_entry(devinfo, &__i2c_board_list, list) { //又见__i2c_board_list,这不是通过i2c_register_board_info组建起来的那个链表吗! if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) //找到总线号与刚注册的这个adapter相同的并通过i2c_new_device进行注册 dev_err(&adapter->dev, \ devinfo->board_info.addr); } up_read(&__i2c_board_lock); //释放读写锁 } 而i2c_board_info成员与i2c_client的对应动作也是在i2c_new_device中进行的,这一点在上边已经分析过了。看到这里,对adapter与client的微妙关系应该了解程度就比较深了,为什么说i2c_register_board_info与i2c_add_numbered_adapter对应而不是i2c_add_adapter也可以说得通。

那么,最终回答开篇提出的那两个问题:

? i2c_adapter驱动如何添加?

板级适配器(CPU自带、主板集成)要通过i2c_add_numbered_adapter注册,注册前要指定总线号,从0开始。假如板级I2C适配器注册了3个,那么第一个动态总线号一定是3,也就是说可插拔设备所带有的I2C适配器需要通过i2c_add_adapter进行注册,其总线号由系统指定。 ? i2c_client与i2c_board_info究竟是什么关系? i2c_client与i2c_board_info的对应关系在i2c_new_device中有完整体现。 i2c_client->dev.platform_data = i2c_board_info->platform_data; i2c_client->dev.archdata = i2c_board_info->archdata; i2c_client->flags = i2c_board_info->flags; i2c_client->addr = i2c_board_info->addr; i2c_client->irq = i2c_board_info->irq; Linux I2C设备驱动编写(三)-实例分析AM3359 TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: ? ? ? ? ? ? ? ? ?

兼容飞利浦I2C 2.1版本规格

支持标准模式(100K bits/s)和快速模式(400K bits/s) 多路接收、发送模式

支持7bit、10bit设备地址模式 32字节FIFO缓冲区 可编程时钟发生器 双DMA通道,一条中断线 三个I2C模块实例I2C0\\I2C1\\I2C2

时钟信号能够达到最高48MHz,来自PRCM

不支持

? ?

SCCB协议

高速模式(3.4MBPS)

管脚

管脚 类型 描述 管脚 I2Cx_SCL I2Cx_SDA 类型 I/OD I/OD 描述 I2C 串行时钟 I2C 串行数据 I2C重置

? ? ?

通过系统重置PIRSTNA=0,所有寄存器都会被重置到上电状态 软重置,置位I2C_SYSC寄存器的SRST位。

I2C_CON寄存器的I2C_EN位可以让I2C模块重置。当PIRSTNA=1,I2C_EN=0会让I2C模块功能部分重置,所有寄存器数据会被暂存(不会恢复上电状态)

数据有效性

?

SDA在SCL高电平期间必须保持稳定,而只有在SCL低电平期间数据线(SDA)才可以进行高低电平切换

开始位&停止位

当I2C模块被设置为主控制时会产生START和STOP:

? START开始位是SCL高电平期间SDA HIGH->LOW SCL _____ _______ \\____/ SDA __

\\____________

? STOP停止位是SCL高电平期间SDA LOW->HIGH SCL _____ _______ \\____/ SDA ___________ __/

? 在START信号后总线就会被认为是busy忙状态,而在STOP后其会被视为空闲状态

串行数据格式

8位数据格式,每个放在SDA线上的都是1个字节即8位长,总共有多少个字节要发送/接收是需要写在DCOUNT寄存器中的。数据是高位先传输,如果I2C模块处于接收模式中,那么一个应答位后跟着一个字节的数据。I2C模块支持两种数据格式:

? ?

7bit/10bit地址格式

带有多个开始位的7bit/10bit地址格式

FIFO控制

I2C模块有两个内部的32字节FIFO,FIFO的深度可以通过控制I2C_IRQSTATUS_RAW.FIFODEPTH寄存器修改。

如何编程I2C

1. 使能模块前先设置

? ? ? ?

使分频器产生约12MHz的I2C模块时钟(设置I2C_PSC=x,x的值需要根据系统时钟频率进行计算) 使I2C时钟产生100Kpbs(Standard Mode)或400Kbps(Fast Mode)(SCLL = x 及 SCLH = x,这些值也是需要根据系统时钟频率进行计算) 如果是FS模式,则配置自己的地址(I2C_OA = x) 重置I2C模块(I2C_CON:I2C_EN=1)

2. 初始化程序

? ? ?

设置I2C工作模式寄存器(I2C_CON)

若想用传输数据中断则使能中断掩码(I2C_IRQENABLE_SET)

如果在FS模式中,使用DMA传输数据的话,使能DMA(I2C_BUF及I2C_DMA/RX/TX/ENABLE_SET)且配置DMA控制器

3. 设置从地址和数据计数器

在主动模式中,设置从地址(I2C_SA = x),设置传输需要的字节数(I2C_CNT = x)

4. 初始化一次传输

在FS模式中。查询一下I2C状态寄存器(I2C_IRQSTATUS_RAW)中总线状态(BB),如果是0则说明总线不是忙状态,设置START/STOP(I2C_CON:STT/STP)初始化一次传输。

5. 接收数据

检查I2C状态寄存器(I2C_IRQSTATUS_RAW)中代表接收数据是否准备好的中断位(RRDY),用这个RRDY中断(I2C_IRQENABLE_SET.RRDY_IE置位)或使用DMA_RX(I2C_BUF.RDMA_EN置位且I2C_DMARXENABLE_SET置位)去数据接收寄存器(I2C_DATA)中去读接收到的数据。

6. 发送数据

查询代表传输数据是否准备好的中断位(XRDY)(还是在状态寄存器I2C_IRQSTATUS_RAW中),用XRDY中断(I2C_IRQENABLE_SET.XRDY_IE置位)或DMA_TX(I2C_BUF.XDMA_EN与I2C_DMATXENABLE_SET置位)去将数据写入到I2C_DATA寄存器中。

I2C寄存器

由于寄存器众多,这里只将上述提到过的几个拿出来(不包含DMA相关)。 偏移量 00h 04h 24h 2Ch 98h 9Ch A4h A8h 寄存器名 I2C_REVNB_LO I2C_REVNB_HI I2C_IRQSTATUS_RAW I2C_IRQENABLE_SET I2C_CNT I2C_DATA I2C_CON I2C_OA 概述 只读,存储着硬烧写的此模块的版本号 只读,存储功能和SCHEME信息 读写,提供相关中断信息,是否使能等 读写,使能中断 读写,设置I2C数据承载量(多少字节),在STT设1和接到ARDY间不能改动此寄存器 读写,8位,本地数据读写到FIFO寄存器 读写,在传输期间不要修改(STT为1到接收到ARDY间),I2C控制设置 读写,8位,传输期间不能修改。设置自身I2C地址7bit/10bit


Linux I2C设备驱动编写 - 图文(5).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:点焊

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: