0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

关于Linux驱动开发的IIC设备驱动的投机取巧

Rice嵌入式开发技术分享 来源: Rice嵌入式开发技术分享 作者: Rice嵌入式开发技 2022-08-09 11:18 次阅读

前言

  • Linux的IIC驱动想必大家都耳熟能详,网上也有很多相关的教程
  • 网上的教程总结,比如:
方法 问题描述
Linux 3.X.X版本之后,设备树+驱动 此方法是比较符合linux驱动的写法的。当对于不熟悉设备树的小伙伴,写起来比较棘手
使用 i2c-tools,并通过脚本或者应用程序编写设备驱动(简单粗暴) 此方法是将设备驱动丢到用户态中,对于一些的设备除了I2C通信还有一些引脚也要控制的,此方法写起来将非常痛苦
直接操作i2c总线驱动。(简单粗暴) 此方法是将设备驱动丢到用户态中,对于一些的设备除了I2C通信还有一些引脚也要控制的,此方法写起来将非常痛苦。他将会操作多个文件
  • 上面的做法都有些困难及弊端存在,经过摸索了一遍Linux的I2C驱动框架,我发现可以很精简的写一个I2C设备的设备驱动。而且是放在内核态中,这样处理一下GPIO或者中断什么的都很方便。

投机取巧的I2C驱动

I2C设备驱动说明

  • 投机取巧的I2C驱动是参考I2C总线驱动代码实现的。
  • 投机取巧的I2C驱动不需要设备树,这也让一些不熟悉设备树的小伙伴能编写一个设备驱动。
  • 投机取巧的I2C驱动精简,方便理解。

分析I2C总线驱动说明

  • I2C总线驱动的代码在linux的源码中--i2c-dev.c中。

  • 在代码中可以看到他提供一套文件操作接口,open,read,write,close接口。实际在上面描述的直接操作i2c总线驱动的方法,最终就是调用到这里。

  • 通过整个源码的分析,我们主要看看open和ioctl接口。其中:

  • open接口,代码分析:通过inode获取设备子设备号,根据子设备号获取I2C适配器。然后申请一个从设备对象。并将I2C适配器句柄映射到从设备对象中。

staticinti2cdev_open(structinode*inode,structfile*file)
{
unsignedintminor=iminor(inode);
structi2c_client*client;
structi2c_adapter*adap;

adap=i2c_get_adapter(minor);
if(!adap)
return-ENODEV;

/*Thiscreatesananonymousi2c_client,whichmaylaterbe
*pointedtosomeaddressusingI2C_SLAVEorI2C_SLAVE_FORCE.
*
*Thisclientis**NEVERREGISTERED**withthedrivermodel
*orI2Ccorecode!!Itjustholdsprivatecopiesofaddressing
*informationandmaybeaPECflag.
*/
client=kzalloc(sizeof(*client),GFP_KERNEL);
if(!client){
i2c_put_adapter(adap);
return-ENOMEM;
}
snprintf(client->name,I2C_NAME_SIZE,"i2c-dev%d",adap->nr);

client->adapter=adap;
file->private_data=client;

return0;
}

  • ioctl接口(只提取有用信息): 获取从设备对象句柄,然后将用户态传输的内容传输到i2cdev_ioctl_rdwr()接口。i2cdev_ioctl_rdwr()接口是i2c总线驱动对从设备操作的进一步封装,我们进一步看一下这个函数。
staticlongi2cdev_ioctl(structfile*file,unsignedintcmd,unsignedlongarg)
{
structi2c_client*client=file->private_data;
unsignedlongfuncs;

......

switch(cmd){
.....

caseI2C_RDWR:
returni2cdev_ioctl_rdwr(client,arg);

......
}
return0;
}
  • i2cdev_ioctl_rdwr接口:通过接口可以看出,从用户态拷贝数据,然后通过i2c_transfer接口进入从设备数据读写,然后判断标志是否读操作,如果为读操作,将i2c_transfer接口接收回来的数据拷贝到用户态。
staticnoinlineinti2cdev_ioctl_rdwr(structi2c_client*client,
unsignedlongarg)
{
structi2c_rdwr_ioctl_datardwr_arg;
structi2c_msg*rdwr_pa;
u8__user**data_ptrs;
inti,res;

if(copy_from_user(&rdwr_arg,
(structi2c_rdwr_ioctl_data__user*)arg,
sizeof(rdwr_arg)))
return-EFAULT;

......

res=i2c_transfer(client->adapter,rdwr_pa,rdwr_arg.nmsgs);
while(i-->0){
if(res>=0&&(rdwr_pa[i].flags&I2C_M_RD)){
if(copy_to_user(data_ptrs[i],rdwr_pa[i].buf,
rdwr_pa[i].len))
res=-EFAULT;
}
kfree(rdwr_pa[i].buf);
}
......

returnres;
}

投机取巧的I2C驱动写法

  • 通过i2c总线驱动的源码分析,实际我们的设备驱动可以通过这种模仿这个总线驱动来写。
  • 代码模板如下:
#include"rice_i2c.h"

#defineCLASS_NAME"rice_i2c"
#defineDEVICE_NAME"rice_i2c"

typedefstruct{
intmajor_number;
structdevice*device;
structclass*class;
structi2c_client*client;
}Rice_Driver;

Rice_Driverrice_drv;

staticinti2c_test(void)
{
structi2c_msgi2c_msg[2]={0};
uint8_treg_addr=0x75;
uint8_tbuff[2]={0};

i2c_msg[0].addr=0x69;
i2c_msg[0].flags=0;
i2c_msg[0].len=1;
i2c_msg[0].buf=(uint8_t*)®_addr;
i2c_msg[1].addr=0x69;
i2c_msg[1].flags=I2C_M_RD;
i2c_msg[1].len=1;
i2c_msg[1].buf=buff;

i2c_transfer(rice_drv.client->adapter,i2c_msg,2);

printk(KERN_ALERT"i2creaddata:0x%02x!!\n",buff[0]);
}

staticint__initrice_i2c_init(void){
structi2c_client*client;
structi2c_adapter*adap;

rice_drv.major_number=register_chrdev(0,DEVICE_NAME,NULL);

if(rice_drv.major_number< 0){
printk(KERN_ALERT"Registerfail!!\n");
returnrice_drv.major_number;
}

printk(KERN_ALERT"Registesuccess,majornumberis%d\n",rice_drv.major_number);

rice_drv.class=class_create(THIS_MODULE,CLASS_NAME);

if(IS_ERR(rice_drv.class)){
unregister_chrdev(rice_drv.major_number,DEVICE_NAME);
returnPTR_ERR(rice_drv.class);
}

rice_drv.device=device_create(rice_drv.class,NULL,MKDEV(rice_drv.major_number,0),NULL,DEVICE_NAME);

if(IS_ERR(rice_drv.device)){
class_destroy(rice_drv.class);
unregister_chrdev(rice_drv.major_number,DEVICE_NAME);
returnPTR_ERR(rice_drv.device);
}

//1为设备挂在的i2c总线的子设备号
adap=i2c_get_adapter(1);
if(!adap)
return-ENODEV;

rice_drv.client=kzalloc(sizeof(*rice_drv.client),GFP_KERNEL);
if(!rice_drv.client){
i2c_put_adapter(adap);
return-ENOMEM;
}
snprintf(rice_drv.client->name,I2C_NAME_SIZE,"i2c-dev%d",adap->nr);

rice_drv.client->adapter=adap;

i2c_test();

printk(KERN_ALERT"ricei2ckoinit!!\n");

return0;
}

staticvoid__exitrice_i2c_exit(void){
device_destroy(rice_drv.class,MKDEV(rice_drv.major_number,0));
class_unregister(rice_drv.class);
class_destroy(rice_drv.class);
unregister_chrdev(rice_drv.major_number,DEVICE_NAME);
i2c_put_adapter(rice_drv.client->adap);

printk(KERN_ALERT"ricei2ckoexit!!\n");
}

module_init(rice_i2c_init);
module_exit(rice_i2c_exit);
MODULE_AUTHOR("RieChen");
MODULE_LICENSE("GPL");

  • 运行结果
Registesuccess,majornumberis240
i2creaddata:0x67!!
ricei2ckoinit!!

总结

  • 通过投机取巧的方法,不需要设备树的存在,就可以在内核态中编写设备驱动,而且很灵活。
  • 虽然这是一种可以让我们快速开发驱动的方法,但是还是建议大家要去了解框架的逻辑。这样不仅对自己的编码能力,以及开发很有帮助。
  • 希望本篇文章能够帮助到大家。

审核编辑 黄昊宇


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 驱动
    +关注

    关注

    11

    文章

    1717

    浏览量

    84340
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206733
  • IIC
    IIC
    +关注

    关注

    11

    文章

    285

    浏览量

    37800
  • 驱动开发
    +关注

    关注

    0

    文章

    129

    浏览量

    12010
收藏 人收藏

    评论

    相关推荐

    Linux驱动开发:字符设备驱动开发理论

    大部分学习者的最终目的就是学习 Linux驱动开发Linux中的外设驱动可以分为:字符设备
    发表于 10-26 09:53 694次阅读

    怎么投机取巧移植RT-Thread到国产MCU上

    KEIL5,IAR。串口助手使用的是SecureCRT。BSP基础工程其实移植RT-THREAD到一些比较通用的内核还是比较方便的,因为可以投机取巧。那接下来告诉你怎么投机取巧移植RT-Thread到国产
    发表于 06-09 10:57

    告诉你怎么投机取巧移植RT-Thread到HC32L136芯片上

    KEIL5,IAR。串口助手使用的是SecureCRT。BSP基础工程其实移植RT-THREAD到一些比较通用的内核还是比较方便的,因为可以投机取巧。那接下来告诉你怎么投机取巧移植RT-Thread到国产
    发表于 09-23 15:51

    嵌入式Linux设备驱动开发

    嵌入式Linux设备驱动开发 Linux 设备驱动
    发表于 09-10 13:10 82次下载
    嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>

    Linux设备驱动开发入门

    本文以快捷而简单的方式讲解如何像一个内核开发者那样开发linux设备驱动. 要开发
    发表于 03-19 14:57 600次下载

    ARM-Linux-IIC设备的添加与驱动实现

    本文分析了ARM-LinuxIIC总线及其设备驱动的层次结构,指出了IIC设备添加与
    发表于 06-13 14:37 57次下载
    ARM-<b class='flag-5'>Linux-IIC</b><b class='flag-5'>设备</b>的添加与<b class='flag-5'>驱动</b>实现

    Linux设备驱动开发详解》第23章、Linux设备驱动的移植

    Linux设备驱动开发详解》第23章、Linux设备驱动
    发表于 10-27 10:58 9次下载
    《<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>详解》第23章、<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b>的移植

    Linux设备驱动开发详解》第20章、USB主机与设备驱动

    Linux设备驱动开发详解》第20章、USB主机与设备驱动
    发表于 10-27 11:04 8次下载
    《<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>详解》第20章、USB主机与<b class='flag-5'>设备</b><b class='flag-5'>驱动</b>

    Linux设备驱动开发详解》第18章、LCD设备驱动

    Linux设备驱动开发详解》第18章、LCD设备驱动
    发表于 10-27 11:11 13次下载
    《<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>详解》第18章、LCD<b class='flag-5'>设备</b><b class='flag-5'>驱动</b>

    Linux设备驱动开发详解》第13章、Linux设备驱动

    Linux设备驱动开发详解》第13章、Linux设备驱动
    发表于 10-27 11:24 18次下载
    《<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>详解》第13章、<b class='flag-5'>Linux</b>块<b class='flag-5'>设备</b><b class='flag-5'>驱动</b>

    Linux设备驱动开发详解》第9章、Linux设备驱动中的异步通知与异步IO

    Linux设备驱动开发详解》第9章、Linux设备驱动
    发表于 10-27 11:33 0次下载
    《<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>详解》第9章、<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b>中的异步通知与异步IO

    Linux设备驱动开发详解》第7章、Linux设备驱动中的并发控制

    Linux设备驱动开发详解》第7章、Linux设备驱动
    发表于 10-27 11:37 10次下载
    《<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>详解》第7章、<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b>中的并发控制

    Linux设备驱动开发详解》第6章、字符设备驱动

    Linux设备驱动开发详解》第6章、字符设备驱动
    发表于 10-27 11:46 23次下载
    《<b class='flag-5'>Linux</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>详解》第6章、字符<b class='flag-5'>设备</b><b class='flag-5'>驱动</b>

    Linux设备驱动开发详解

    Linux设备驱动开发详解
    发表于 10-28 11:03 45次下载

    ARM-Linux-IIC设备的添加与驱动实现

    电子发烧友网站提供《ARM-Linux-IIC设备的添加与驱动实现.pdf》资料免费下载
    发表于 10-24 09:55 0次下载
    ARM-<b class='flag-5'>Linux-IIC</b><b class='flag-5'>设备</b>的添加与<b class='flag-5'>驱动</b>实现