Linux系统中I2C总线设备的驱动设计

 具体在linux中AT91RM9200 I2C总线适配器驱动的实现,首先初始化AT91RM9200 I2C的工作模式,然后装载I2C总线驱动,这需要两个结构模块来描述:struct i2c_adapter和struct i2c_algorithm。

初始化i2c_adapter结构成员如下:
static struct i2c_adapter at91rm9200_adapter = {
name:           AT91RM9200,   
id:             I2C_ALGO_SMBUS,   
algo:           &at91_algorithm,   
algo_data:      NULL,   
inc_use:        at91_inc,   
dec_use:        at91_dec,   
... ...
};

这个模块并未提供读写函数,具体的读写方法由第二个模块struct i2c_algorithm提供。
static struct i2c_algorithm at91_algorithm = {
name:  at91 i2c,
id:  I2C_ALGO_SMBUS,
smbus_xfer: at91_smbus_xfer,
master_xfer: at91_xfer,
functionality: at91_func,
};

通过调用I2C core中的接口函数i2c_add_adapter将这两个模块注册到操作系统里,总线驱动就算装上了。由此可见,i2c_algorithm实现了i2c通信具体方法。针对本文at91rm9200 I2C适配器, at91_xfer最为关键。分析内核可知,I2C core框架中提供给主机使用的数据传输接口:i2c_master_send,i2c_master_recv,i2c_transfer最终都是通过调用at91_xfer实现。

数据传输处理如下:数据发送主机初始化Start状态后,向主机模式寄存器TWI_MMR中DADR发送一个7位从机地址,以通知从机器件。从机地址后的位表示传输方向(写或读)。该位为0,说明是写操作(发送操作);若该位为1,说明为数据读请求( 接收操作)。TWI 传输要求从机每收到一个字节后均要给出应答。在应答时钟脉冲中,主机释放数据线(HIGH),将从机拉低以产生应答。主机在该时钟脉冲中轮询数据线,可使用轮询或中断方式来检验状态位。若从机未应答该字节,将置位状态寄存器TWI_SR的NAK 位。

写操作则发送数据至保持寄存器TWI_THR,设置TWI_CR的START 位以启动传输。数据在内部移位寄存器中移位,当检测到应答,TXRDY位置位,直到TWI_THR中有新数据写入,才清除该位。主机产生STOP 状态来结束传输。设置START 后开始读序列。当状态寄存器中RXRDY 位置位时,接收保持寄存器(TWI_RHR)以收到一个字符。当读TWI_RHR 时RXRDY 位复位。

TWI接口可执行多种传输格式:7位从机地址和10位从机地址。通过主机模式寄存器TWI_MMR配置三个内部地址字节。若从机仅支持7 位地址,IADRSZ 必须置为0。若从机地址大于7 位,用户必须配置地址大小IADRSZ 并在内部地址寄存器TWI_IADR中设置其他从机地址位。

X1227的设备驱动实现

X1227 是一个带有时钟、日历、CPU 监控电路和两路查询报警的实时时钟。时钟使用一个低成本的32.768kHz 的晶体作为输入,可精密地用秒、分钟、小时、日期、星期、月、年来显示时间,它可以自动调整闰年至2096年。同时X1227有一个看门狗定时器、3个超时时间可供选择。另外,X1227有一个4K位的EEPROM阵列,可用作某些用户配置数据的存储器。下面以X1227为例,说明一个具体的I2C设备驱动程序的设计要点。

如前所述,I2C总线驱动只是提供了对一条总线的读写机制,本身并不会去做通信。通信是由I2C设备驱动来做的,设备驱动透过I2C总线同具体的设备进行通讯。一个设备驱动有两个模块来描述,struct i2c_client和struct i2c_driver。i2c_client用来描述一个具体的I2C设备,i2c_driver结构提供了i2c_adapter与i2c_client之间的通信方式。

struct i2c_driver x1227_driver = {
name:  襒1227?
id:  I2C_DRIVERID_X1227,
flags:  I2C_DF_NOTIFY,
attach_adapter: x1227_probe,
detach_client: x1227_detach,
command: x1227_command
};

其中:attach_adapter利用适配器驱动提供的I2C总线访问方法,利用设备驱动程序模块中提供的地址线索信息,检测可能存在的设备及其地址。如果成功发现设备,则创建一个struct i2c_client来标识这个设备,并向该适配器的数据结构注册。detach_client用于从总线上注销设备、并释放i2c_client及相应的私有数据结构。command是用户接口中的ioctl功能的底层实现。

I2C设备驱动需要实现两个方面的接口,一个是对I2C core框架的接口,设备初始化时通过函数i2c_add_driver调用,来实现驱动的注册。这个i2c_driver一旦装入完成,其中的attach_adapter函数就会被调用。

另一个是对用户应用层的接口,提供用户程序访问I2C设备的接口,包括实现open,release,read,write以及最重要的ioctl等标准文件操作的接口函数。每个设备驱动程序都有一个称为file_operations的数据结构,用来实现接口函数。

static struct file_operations rtc_fops = {
owner:  THIS_MODULE,
ioctl:  x1227_rtc_ioctl,
open:  x1227_rtc_open,
release: x1227_rtc_release,
};

其中open和release用来打开和关闭X1227,x1227_rtc_ioctl则向用户提供的一系列控制时钟芯片的具体命令:RTC_GET_TIME(以固定的数据格式读取实时时钟的时间)、RTC_SET_TIME(以固定的数据格式设定实时时钟的时间)以及E2PROM读写等。

对于X1227,一般注册为一个miscdevice设备(所有miscdevice设备共同一个主设备号,不同的次设备号)。

static struct miscdevice x1227_rtc_miscdev = {
RTC_MINOR,
tc?
&rtc_fops
};

初始化时,通过misc_register (&x1227_rtc_miscdev)注册X1227,这样用户程序可以通过主设备号10 次设备号 135的设备节点/dev/rtc来访问X1227。

要测试X1227的时钟功能,首先把AT91RM9200的I2C总线驱动模块和X1227模块在系统启动时先后加载。需要指出的是,Linux将时钟分为系统时钟和硬件时钟两种。系统时钟是指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的那个主板硬件时钟,也就是本文中的X1227。

在Linux中,用于时钟查看和设置的命令主要有date、hwclock。首先设置系统时钟,比如设置为2006年8月17日12点30分:date 081712302006,然后设置硬件时钟为当前系统时钟时间,使用命令/sbin/hwclock 衧ystohc,则X1227中的时间设置为当前系统时间。然后,通常在操作系统启动时设置启动脚本/sbin/hwclock 衕ctosys,利用X1227内的时间更新系统时钟,然后直到重启或关闭系统,由系统时钟来记录时间。

结语

本文介绍了I2C总线适配器及I2C设备驱动的实现。该设计成功用于某网络测试设备的主控模块上,实现了设备的实时时钟功能,便于整个系统的监控。I2C总线在目前的嵌入式领域中应用非常广泛,如音/视频的控制,存储设备的通讯等,而Linux也已成为嵌入式系统的主流。从linux内核看,I2C的驱动程序具有清晰的层次结构,为编程者开发I2C相关驱动提供了规范的框架。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值