linux设备驱动程序——i2c设备驱动源码实现

(基于4.14内核版本)
为了梳理清楚linux内核中的i2c实现框架,从本文开始,博主将分几个章节分别解析i2c总线在linux内核中的形成过程、匹配过程、以及设备驱动程序源码实现。

在介绍linux内核中i2c框架之前,我们最好是知道怎么使用它,实现一个相应的i2c设备驱动程序demo,然后从使用去深挖背后的实现原理,先知道怎么用,然后再知道为什么可以这么用。

I2C的基本知识扫盲

回到本文的重点——I2C,做过裸板开发或者是单片机开发的朋友肯定对I2C不陌生,I2C是主从结构,主器件使用从机地址进行寻址,它的拓扑结构是这样的:

基本的流程是这样的:

  • 主机发送从机地址
  • 从机监听总线,检测到接收地址与自身地址地址匹配,回复。
  • 主机启动收发数据
  • 从机接收数据,响应
  • 数据收发完毕,主机释放总线。
    完整的I2C操作其实是比较复杂的,这里就不再展开讲解,博主将会在随后的章节中进行详解。

I2C设备驱动程序框架

I2C设备驱动程序框架分为两个部分:driver和device。

分别将driver和device加载到内存中,i2c bus在程序加载时会自动调用match函数,根据名称来匹配driver和device,匹配完成时调用probe()

在driver中,定义probe()函数,在probe函数中创建设备节点,针对不同的设备实现不同的功能。

在device中,设置设备I2C地址,选择I2C适配器。

I2C适配器:I2C的底层传输功能,一般指硬件I2C控制器。

I2C设备驱动程序

driver端示例

直接来看下面的示例代码:
i2c_bus_driver.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

/* 结构体数组 结构体第一个参数为名称,第二个参数为private数据*/
static const struct i2c_device_id downey_drv_id_table[] = {
    {"downey_i2c",0},
    {},
};

static int major;
static struct class *i2c_test_cls;
static struct device *i2c_test_dev;
static const char* CLASS_NAME = "I2C_TEST_CLASS";
static const char* DEVICE_NAME = "I2C_TEST_DEVICE";

static struct i2c_client *downey_client;


static int i2c_test_open(struct inode *node, struct file *file)
{
    printk(KERN_ALERT "i2c init \n");
    return 0;
}

static ssize_t i2c_test_read(struct file *file,char *buf, size_t len,loff_t *offset)
{
    int cnt = 0;
    uint8_t reg = 0;
    uint8_t val = 0;
    copy_from_user(&reg,buf,1);
    /*i2c读byte,通过这个函数可以从设备中指定地址读取数据*/
    val = i2c_smbus_read_byte_data(downey_client,reg);
    cnt = copy_to_user(&buf[1],&val,1);
    return 1;
}

static ssize_t i2c_test_write(struct file *file,const char *buf,size_t len,loff_t *offset)
{
    uint8_t recv_msg[255] = {0};
    uint8_t reg = 0;
    int cnt = 0;
    cnt = copy_from_user(recv_msg,buf,len);
    reg = recv_msg[0];
    printk(KERN_INFO "recv data = %x.%x\n",recv_msg[0],recv_msg[1]);
    /*i2c写byte,通过这个函数可以往设备中指定地址写数据*/
    if(i2c_smbus_write_byte_data(downey_client,reg,recv_msg[1]) < 0){
        printk(KERN_ALERT  " write failed!!!\n");
        return -EIO;
    }
    return len;
}

static int i2c_te
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值