新手写LinuxI2C驱动程序

Linux下i2c驱动

接下来将是一个新手去写i2c驱动,这个驱动也是自己第一次写,用了2天时间去学习,最后终于完成,在写驱动之前,我们需要搞明白以下几点

  • Linux怎么识别我们的i2c芯片
  • 怎么去写
  • 什么是设备地址

首先我们需要明白一个I2C驱动在单片机上面怎么写,这个时候就需要去网上了解以下I2C的基础知识,同时自己也要认真研究自己的芯片手册,我这里用的是TCA9555这个I2C芯片

查了网上的资料,大致总结一下,一个I2C驱动可以由以下几个不同的方式来完成:
(1)使用gpio模拟i2c协议
(2)使用Linux系统中的I2C体系

1、使用gpio模拟i2c协议
我最开始就是想到这种方法,当然这种方法还是单片机的思维,感觉自己目前还是缺少Linux系统的思维,这个需要多练,培养自己的Linux思维,在用gpio模拟i2c协议时,我们需要知道引脚的地址,然后去按照单片机的方法去写,很麻烦,我在这个过程中,是完全不了解I2C引脚的地址怎么去获取,然我在这里卡了很久,感觉这条路行不通

2、使用Linux系统中的I2C体系
很明显,我们的i2c一般都是接在处理器的I2C接口上面的(我用的是AM335X),此时我们需要做的就是让处理器知道,我们需要使用这个I2C,说道这里,也就是关键的部分—-如何注册我们的设备(让整个系统知道)查了很多资料,大致有以下几种方法:
(1)在、arch/arm/目录下找到对应的mach文件进行注册
static struct i2c_board_info h4_i2c_board_info[] __initdata = {
{
I2C_BOARD_INFO(“isp1301_omap”, 0x2d),
.irq = OMAP_GPIO_IRQ(125),
},
这一种方法我也没搞太懂,不过可以确定的是,在Linux内核加入设备树概念后,我们用设备树会更清楚明白
(2)设备树进行注册(我用的方法)
&i2c1 {
pinctrl-names = “default”;
pinctrl-0 = <&i2c1_pins>;

    status = "okay";
    clock-frequency = <400000>;

    tca9555: tca9555@20 {
            compatible = "ti,tca9555";
            reg = <0x20>;
    };

此时就面临一个问题,设备树怎么注册,首先我们搞清楚设备地址这个概念:研究了一下,说白了就是看芯片手册,我的是
这里写图片描述
可以看到,只需知道A2A1A0就可,然后看一下自己的电路图,查看一下A2A1A0的连接情况,我的都是接地,然后在最高位补上0,就确定了我的设备地址为0x20,从而就可以注册设备树
注册完了之后,我们就解决了第一个问题,让Linux系统知道有这个设备存在,接下来我们要做的就是,具体的驱动与Linux系统的握手,
(3)还有很多方法,我也没有研究

设备驱动怎么写

首先我们需要程序入口和出口:

“`
static int __init tca9555_init(void)
{
printk(DEVICE_NAME”\tinitialized\n”);
i2c_add_driver(&tca9555_driver);
return 0;
}

static void __exit tca9555_exit(void)
{
i2c_del_driver(&tca9555_driver);
}
调用系统中的i2c_add_driver(i2c_del_driver)来增加(卸载)自己的i2c设备

然后写tca9555_dristatic ,按照i2c_driver结构体的格式来写
struct i2c_driver tca9555_driver = {
.driver.name = “tca9555”,
.id_table = tca9555_id,
.probe = tca9555_probe,
.remove = tca9555_remove,
};

填写tca9555_static
const struct i2c_device_id tca9555_id[]={
{“tca9555”,0}, //这里的名字一定要与设备树中的一致
{ /* end of list */ },
};

构建tca9555_probe函数,此函数主要用来匹配
static int tca9555_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ //匹配不成功,设备节点不能注册
printk(“misc ok\n”);
misc_register(&tca9555_dev); //混杂设备
g_client = client;
return 0;
}

构建tca9555_remove函数用来注销设备
static int tca9555_remove(struct i2c_client *client)
{
misc_deregister(&tca9555_dev);
g_client = NULL;
return 0;
}

因为我们在上面注册了misc设备,此时接下来就是混杂设备驱动的编写过程,首先构建一个结构体,由结构体引出我们需要处理的函数

static struct miscdevice tca9555_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = “tca9555_i2c”,
.fops = &tca9555_fops
};

static struct file_operations tca9555_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = tca9555_ioctl
};

然后,我们应用程序与驱动之间的通信就靠tca9555_ioctl这个函数来完成了,着这个过程中,我们如何达成I2C之间的通信,其实是调用i2c_smbus_read_byte_data和i2c_smbus_write_byte_data这个函数来完成的,这个函数是Linux内置函数,我们需要用一个
tca9555_i2c_read来将其进行封装:

static unsigned char tca9555_i2c_read(unsigned char addr)
{
return i2c_smbus_read_byte_data(g_client,addr);
}

从而,在ioctl的时候方便调用

差不多内容就是这么多,驱动源代码和测试程序我会在文章最后给大家,总结的来说,此I2C驱动对于很多新手来说很难是因为,不知道Linux里面有I2C体系,然后知道了I2C体系后,网上也是各种方法都有,搞得人很混乱,从而无从下手,我也是根据网上的博客模仿写出来的

最后总结一下:
(1)首先注册,让系统知道硬件的存在
(2)如何握手,调用I2C_ADD_DRIVER,然后调用id probe来匹配我们的驱动(匹配不成功,程序不会往下走,也就是说,设备节点注册不成功)
(3)匹配成功后,调用misc设备的注册方法,注册我们的设备,写ioctl函数,进行应用程与驱动层的通信
(4)利用系统I2C通信函数,我们用自己的函数对其进行封装即可

这是第一篇博客文章,以前好多次想写来着,但最后忙着其他事也就忘记了,以后会把自己这段时间做的东西跟大家分享一下,希望大家多多交流

[我参考的文章]
http://blog.csdn.net/borntox/article/details/51878089

[i2c驱动和测试代码]
http://download.csdn.net/detail/lixiaojie123123/9836768

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值