前段时间写了一篇文章,
《手把手教你写Linux I2C设备驱动》,是基于Linux2.6.18内核,使用的是老的I2C Client驱动模型,这篇文章基于Linux2.6.32内核,采用新的I2C Client驱动模型,给出I2C驱动的编写示例,主要给出驱动层代码的示例,其他内容参考
《Linux下读写芯片的I2C寄存器》,
《用户空间访问I2C设备驱动》这两篇文章。
闲话不说,先给出完整的示例代码,加好注释,后面再进一步解释。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define I2C_DEV_NAME "MyDevice" //这个名字要跟board_info中的名字一致,才会与I2C_Client匹配
-
-
static struct i2c_device_id my_id[] = {
-
{I2C_DEV_NAME,0},
-
{}
-
};
-
-
MODULE_DEVICE_TABLE(i2c, my_id);
-
-
-
static struct i2c_client *my_client;
-
-
-
static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
-
{
-
-
my_client = client;
-
-
return 0;
-
}
-
-
static int my_i2c_remove(struct i2c_client *client)
-
{
-
//释放I2C Client对象
-
if( my_client != NULL ) {
-
i2c_unregister_device(my_client);
-
}
-
return 0;
-
}
-
-
static struct i2c_driver my_driver = {
-
.driver = {
-
.name = "my i2c driver",
-
.owner = THIS_MODULE,
-
},
-
.probe = my_i2c_probe,
-
.remove = __devexit_p(my_i2c_remove),
-
.id_table = my_id,
-
};
-
-
static int __init my_i2c_init(void)
-
{
-
-
return i2c_add_driver(&my_driver);
-
}
-
-
static void __exit my_i2c_exit(void)
-
{
-
-
i2c_del_driver(&my_driver);
-
}
-
-
int my_i2c_write( uint8_t reg,uint8_t data )
-
{
-
unsigned char buffer[2];
-
buffer[0] = reg;
-
buffer[1] = data;
-
-
if( 2!= i2c_master_send(my_client,buffer,2) ) {
-
printk( KERN_ERR "my i2c send fail! \n" );
-
return -1;
-
}
-
return 0;
-
}
-
-
int my_i2c_read( uint8_t reg,uint8_t *data )
-
{
-
-
if( 1!= i2c_master_send(my_client,®,1) ) {
-
printk( KERN_ERR "my i2c recv fail! \n" );
-
return -1;
-
}
-
-
msleep(10);
-
-
if( 1!= i2c_master_recv(my_client,data,1) ) {
-
printk( KERN_ERR "my i2c recv fail! \n" );
-
return -1;
-
}
-
-
return 0;
-
}
-
-
MODULE_DESCRIPTION("my i2c driver");
-
MODULE_AUTHOR("Lujun @HUST");
-
MODULE_LICENSE("GPL");
-
-
module_init(my_i2c_init);
-
module_exit(my_i2c_exit);
上面的代码还不能完全成功运行,因为还没有添加自己的I2C设备信息到系统中,模块Probe函数不会被调用执行。注释中已经提到,i2c_add_driver的时候会扫描本模块的 id_table 中的名称是否与注册到系统中的boardinfo列表中有名称匹配的client,如果有,则会构造 i2c_client 对象,并调用本模块的 probe 函数。
那么,如何注册自己的i2c设备信息到系统的 boardinfo 列表中呢?Linux内核文档:Documentation/i2c/instantiating-devices 中讲了多种方式,我在此只说2种方式。
第一种方式,在内核的初始化中定义你的I2C设备的信息。比如在/arch/arm/mach-xxxx/board_xxxx.c 中添加一个新的 Boardinfo信息:
-
static struct i2c_board_info __initdata i2c_info[] = {
-
{
-
I2C_BOARD_INFO("24c256", 0x50),
-
.platform_data = &eeprom_info,
-
},
-
{
-
I2C_BOARD_INFO("MyDevice", (0xbc>>1)),
-
.platform_data = NULL,
-
},
-
};
注意,添加的新的 I2C_BOARD_INFO的名称一定要与本模块的driver的名称字符串一致,地址是I2C设备地址右移1位以后的地址。
第二种方式,使用i2c_new_device()。相关函数如下:
-
-
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
-
-
-
struct i2c_adapter* i2c_get_adapter(int id);
-
-
-
ls /sys/class/i2c-adapter/
-
那么,使用第二种方式的示例代码如下,在 my_i2c_init 函数开头,添加如下代码,动态注册 I2C 设备信息到内核 Boardinfo 列表中。
-
-
static struct i2c_board_info my_dev_info[] __initdata = {
-
{
-
I2C_BOARD_INFO(I2C_DEV_NAME,I2C_DEV_ADDR),
-
.platform_data= NULL,
-
},
-
};
-
-
-
static int sys_adap_bus_num = 0;
-
-
static int __init my_i2c_init(void)
-
{
-
struct i2c_adapter* adap = i2c_get_adapter(sys_adap_bus_num);
-
-
if(adap==NULL) {
-
printk("[LUJUN-DEBUG] i2c_get_adapter fail!\n");
-
return -1;
-
}
-
-
-
my_client = i2c_new_device(adap, &my_dev_info[0]);
-
if( my_client==NULL ){
-
printk("[LUJUN-DEBUG] i2c_new_device fail!\n");
-
return -1;
-
}
-
-
-
i2c_put_adapter(adap);
-
-
-
return i2c_add_driver(&my_driver);
-
}
到此为止,我想基于Linux2.6.32的新的I2C Driver模型的编写示例已经基本上说清楚了。如果发现文中有错误的地方或者不清楚的地方.
原文地址:http://ticktick.blog.51cto.com/823160/971738
阅读(1554) | 评论(0) | 转发(0) |