一:I2C设备操作方式:

1.  应用程序操作法:i2c的设备的驱动可以直接利用linux内核提供的i2c-dev.c文件提供的ioctl函数接口在应用层实现对i2c设备的读写,但是在应用层使用ioctl函数对应用程序员要求较高,需要自行构建msg结构体,必须了解设备的操作流程,时序之类的。

这方式实现需要用用程序员调用 read, write, ioctl, open, close等linux标准文件接口操作/dev/i2c(X)设备文件。

2. 驱动程序操作法:i2c设备的驱动也可以通过普通的设备驱动实现,像往常的驱动一样实现,然后在应用层就可以像读取普通文件一样操作,无需再考虑读写时序。其实普通的设备驱动也可以用两种方法实现,

1)构建字符设备驱动,在open,read,write等函数中直接操作i2c总线的相关寄存器来读写i2c设备,但是这种方法因平台不同,设备不同都要重新写驱动

2)在设备驱动中调用i2c-core.c提供的i2c_transfer函数来实现和i2c设备的通信,这样只要对不同的设备写不同的驱动就行了。

二:首先我们来看一看应用程序操作法:

标准i2c接口提供的标准的设备/dev/i2c,首先我们看看linux下标准i2c的结构。

在/linux-kernel-3.8/drivers/i2c目录下

----Algos/                  一些i2c总线适配器通信的算法,个人感觉是用I/O口模拟实现i2c通信的算法

----Busses/               I2C总线驱动的方法,对应于君正4775适配器驱动的文件是i2c-jz4775.c

----Chips/                 I2C设备驱动,具体到某个设备,比如at24c08等

----I2c-boardinfo.c     定义i2c_register_board_info 注册i2c设备相关信息(其实就是将要注册的i2c设备添加到i2c设备链表)

----I2c-core.c           I2C核心文件,用于联系设备驱动和总线驱动,作为一个桥梁,有用的函数i2c_add_addapter

i2c_add_driver,和i2c_transfer函数 (其实就是定义了一些标准的API接口函数)

----I2c-dev.c            通用的i2c设备驱动(其实就是生成的标准的/dev/i2c字符设备文件接口)

----Kconfig

----Makefile

我们要选择编译/linux-kernel-3.8/drivers/i2c/相关的platform driver和arch/mips/xburst/soc-4775/board//trunk/core/core-misc.c相结合最终生成的固件就会有/dev/i2c0标准接口。

以下是笔者做qn8025FM驱动时写下的通过标准i2c设备文件实现的读写函数:通过这两个读写函数就可以直接读写i2c设备的寄存器实现想用的功能

/*
* Version: V1.0.2.
* Date: 2014-11-25.
*/

#include "qn8025_i2c.h"

/*源头即是  IOCTL 呼叫, 通道为 I2C_SMBUS,
而 args 则定义了: 读或写, 位置, 长度,  以及回传值的资讯内容.*/
//ioctl(file, I2C_SMBUS, (i2c_smbus_ioctl_data*)msgset);
static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
                                     int size, union i2c_smbus_data *data)
{
    struct i2c_smbus_ioctl_data args;

args.read_write = read_write;
    args.command = command;
    args.size = size;
    args.data = data;
    int ret=  ioctl(file,I2C_SMBUS,&args);//set Smbus transfer
    //printf("ioctl-read_i2c: %#x\n", args.data->byte);
    return ret;
}

//向设备发送一个比特
static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
{
    return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,(union i2c_smbus_data *)0);
}
   
static inline __s32 i2c_smbus_read_byte(int file)
{
    union i2c_smbus_data data;
    if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
        return -1;
    else
        return 0x0FF & data.byte;
}

static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
{
    return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
                            I2C_SMBUS_BYTE,(union i2c_smbus_data *)0);
}

static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
{
    union i2c_smbus_data data;
    data.byte = 0;
//    printf("before read_byte: %#x\n", data.byte);
    if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
                         I2C_SMBUS_BYTE_DATA,&data))
        return -1;
    else{
//        printf("read_byte: %#x\n", data.byte);
        return 0x0FF & data.byte;
        }
}

static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
                                              __u8 value)
{
    union i2c_smbus_data data;
    data.byte = value;
//    printf("before write_byte: %#x\n", data.byte);
    int ret = i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
                            I2C_SMBUS_BYTE_DATA, &data);
//    printf("write_byte: %#x\n", data.byte);
    return ret;
}

static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
{
    union i2c_smbus_data data;
    if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
                         I2C_SMBUS_WORD_DATA,&data))
        return -1;
    else
        return 0x0FFFF & data.word;
}

static inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
                                              __u16 value)
{
    union i2c_smbus_data data;
    data.word = value;
    return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
                            I2C_SMBUS_WORD_DATA, &data);
}

static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
{
    union i2c_smbus_data data;
    data.word = value;
    if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
                         I2C_SMBUS_PROC_CALL,&data))
        return -1;
    else
        return 0x0FFFF & data.word;
}

/* Returns the number of read bytes */
static inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
                                              __u8 *values)
{
    union i2c_smbus_data data;
    int i;
    if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
                         I2C_SMBUS_BLOCK_DATA,&data))
        return -1;
    else {
        for (i = 1; i <= data.block[0]; i++)
            values[i-1] = data.block[i];
        return data.block[0];
    }
}

static inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
                                               __u8 length, const __u8 *values)
{
    union i2c_smbus_data data;
    int i;
    if (length > 32)
        length = 32;
    for (i = 1; i <= length; i++)
        data.block[i] = values[i-1];
    data.block[0] = length;
    return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
                            I2C_SMBUS_BLOCK_DATA, &data);
}

/* Returns the number of read bytes */
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
   ask for less than 32 bytes, your code will only work with kernels
   2.6.23 and later. */
static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
                                                  __u8 length, __u8 *values)
{
    union i2c_smbus_data data;
    int i;

if (length > 32)
        length = 32;
    data.block[0] = length;
    if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
                         length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
                          I2C_SMBUS_I2C_BLOCK_DATA,&data))
        return -1;
    else {
        for (i = 1; i <= data.block[0]; i++)
            values[i-1] = data.block[i];
        return data.block[0];
    }
}

static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
                                                   __u8 length,
                                                   const __u8 *values)
{
    union i2c_smbus_data data;
    int i;
    if (length > 32)
        length = 32;
    for (i = 1; i <= length; i++)
        data.block[i] = values[i-1];
    data.block[0] = length;
    return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
                            I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
}

/* Returns the number of read bytes */
static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
                                                 __u8 length, __u8 *values)
{
    union i2c_smbus_data data;
    int i;
    if (length > 32)
        length = 32;
    for (i = 1; i <= length; i++)
        data.block[i] = values[i-1];
    data.block[0] = length;
    if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
                         I2C_SMBUS_BLOCK_PROC_CALL,&data))
        return -1;
    else {
        for (i = 1; i <= data.block[0]; i++)
            values[i-1] = data.block[i];
        return data.block[0];
    }
}

//检测i2c设备功能
/*static int check_funcs(int file, int size, int daddress, int pec)
{
    unsigned long funcs;

//check adapter functionality
    if (ioctl(file, I2C_FUNCS, &funcs) < 0) {//获取i2c设备支持的功能
        fprintf(stderr, "Error: Could not get the adapter "
            "functionality matrix: %s\n", strerror(errno));
        return -1;
    }

switch (size) {
    case I2C_SMBUS_BYTE:
        if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
            fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
            return -1;
        }
        if (daddress >= 0
         && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
            fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
            return -1;
        }
        break;

case I2C_SMBUS_BYTE_DATA:
        if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
            fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
            return -1;
        }
        break;

case I2C_SMBUS_WORD_DATA:
        if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
            fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
            return -1;
        }
        break;
    }
    if (pec
     && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
        fprintf(stderr, "Warning: Adapter does "
            "not seem to support PEC\n");
    }

return 0;
}
*/

//设置i2c从设备地址
static int set_slave_addr(int file, int address, int force)
{
    /* With force, let the user read from/write to the registers
       even when a driver is also running */
    if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {
        fprintf(stderr,
            "Error: Could not set address to 0x%02x: %s\n",
            address, strerror(errno));
        return -errno;
    }

return 0;
}

//打开i2c设备
static int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet)
{
    int file;

snprintf(filename, size, "/dev/i2c/%d", i2cbus);
    filename[size - 1] = '\0';
    file = open(filename, O_RDWR);//打开i2c设备
    if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) {
        sprintf(filename, "/dev/i2c-%d", i2cbus);
        file = open(filename, O_RDWR);
    }

if (file < 0 && !quiet) {
        if (errno == ENOENT) {
            fprintf(stderr, "Error: Could not open file "
                "`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
                i2cbus, i2cbus, strerror(ENOENT));
        } else {
            fprintf(stderr, "Error: Could not open file "
                "`%s': %s\n", filename, strerror(errno));
            if (errno == EACCES)
                fprintf(stderr, "Run as root?\n");
        }
    }

return file;
}

//向i2c设备写数据 (0, 0x58,  , 9300, 0)
static int i2c_write_data(int i2cbus,int addr,int daddr,int set_val,int vmask)
{
    int res, file;
    int value;
    char filename[20];

//打开设备描述符,可以自动寻找合适的设备名
    file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
    if (file < 0 || set_slave_addr(file, addr, 1)) {
    //    perror("open i2c");
        printf("open %s fail\n", filename);
        return -1;
    }

//掩码,可以单独设置某一位而不影响其他位
    if (vmask) {
        int oldvalue;

oldvalue = i2c_smbus_read_byte_data(file, daddr);
    printf("write and read\n");
        if (oldvalue < 0) {
            fprintf(stderr, "Error: Failed to read old value\n");
            close(file);
            return -1;
        }

value = (set_val & vmask) | (oldvalue & ~vmask);
    } else {
        value = set_val;
    }

res = i2c_smbus_write_byte_data(file, daddr, value);
    if (res < 0) {
        fprintf(stderr, "Error: Write failed\n");
        close(file);
        return -1;
    }

//res = i2c_smbus_read_byte_data(file, daddr);
   
    close(file);

//if (res < 0) {
    //    printf("Warning - readback failed\n");
    //} else
    //if (res != value) {
    //    printf("Warning - data mismatch - wrote 0x%0*x, read back 0x%0*x\n",2,value,2, res);
    //} else {
        //printf("Value 0x%0*x written, readback matched\n",2, value);
       
        return 0;//读到的值和写入的值一致,才返回成功
    //}

//return -1;
}

//从i2c读取数据
static int i2c_read_data(int i2cbus,int addr,int daddr,unsigned char *read_data)
{
    int file,res;
    char filename[20] = {0};
    //打开i2c设备
    file = open_i2c_dev(0, filename, sizeof(filename), 0);
    if (file < 0 || set_slave_addr(file, addr, 1))//设置从设备地址
        return -1;

res = i2c_smbus_read_byte_data(file, daddr);
    close(file);

if (res < 0) {
        fprintf(stderr, "Error: Read failed\n");
        return -1;
    }

*read_data = res;
    //printf("read data -- 0x%x\n",*read_data);

return 0;
}

/* qn8025 set "set_value" to register "daddr"
addr: slave address
daddr: register address
set_val: the value wiil put into register
vmask: value maske
*/
int qn8025_i2c_write_data(int addr, int daddr, int set_val, int vmask)
{
    return i2c_write_data(0, addr, daddr, set_val, vmask);
}

/* qn8025 get "read_data" from register "daddr"
addr: slave address
daddr: register address
set_val: the value wiil get from register
*/
int qn8025_i2c_read_data(int addr, int daddr, unsigned char *read_data)
{
    return i2c_read_data(0, addr, daddr, read_data);
}

linux 标准i2c接口(一)的更多相关文章

  1. 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口

    最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...

  2. 嵌入式Linux内核I2C子系统详解

    1.1 I2C总线知识 1.1.1  I2C总线物理拓扑结构     I2C总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成.通信原理是通过对SCL和SDA线高 ...

  3. (6)s3c2440用I2C接口访问EEPROM

    在前面阅读理解了I2C的官方协议文档后,就拿s3c2440和EEPROM来验证一下. 本来是想用s3c2440的SDA和SCL管脚复用为GPIO来模拟的,但在没有示波器的情况下搞了一周,怎么都出不来, ...

  4. linux下i2c的驱动架构分析和应用

    i2c在linux下的代码在/driver/i2c下面,总体代码如下所示: i2c-core.c 这个文件实现了I2C核心的功能以及/proc/bus/i2c*接口.    i2c-dev.c  实现 ...

  5. 【驱动】linux下I2C驱动架构全面分析

    I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线. ...

  6. linux文件锁的应用,POSIX,unix标准,linux标准

    1. perl,flock加锁.java也能加锁. 2. 先创建文件并打开,才能加锁(写打开?). 3. 可以用于判断进程是否一直在运行(用另一进程判断),如果锁一直在,则进程在:锁不在,则原进程或意 ...

  7. linux下I2C驱动架构全面分析【转】

    本文转载自:http://blog.csdn.net/wangpengqi/article/details/17711165 I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一 ...

  8. 为 MaixPy 加入软 I2C 接口(移植 MicroPython 的 I2C)

    起因 本文的重心为讲解如何为一款芯片移植和实现 micropython 的通用组件,但会顺带解释不同芯片的工作方式和特性. 国际惯例,先有起因,再谈问题的解决,所以记得上次总结的 关于 K210 Ma ...

  9. linux标准io的copy

    ---恢复内容开始--- 1.linux标准io的copy #include<stdio.h> int main(int argc,char **argv) { if(argc<3) ...

随机推荐

  1. 【Luogu】P3856公共子串(DP)

    题目链接 DP.设last[i][j]是第i个串字符'j'所在的最后的位置,f[i][j][k]是第一个串匹配到i,第二个串匹配到j,第三个串匹配到k,最多的公共子串数. 那么我们三重循环i.j.k, ...

  2. 【Luogu】P3376网络最大流模板(Dinic)

    最大流模板成为另一个被攻克的模板题. 今天QDC给我讲了一下Dinic,感觉很好懂.于是为了巩固就把这道题A掉了. 核心思想就是不断BFS分层,然后不断DFS找增广路.找不到之后就可以把答案累加输出了 ...

  3. mysql5.7.23版本安装教程

    亲身实践安装mysql,用时居然花费了三个小时,在有那么多教程的情况下,依然在不该花费时间的路上浪费了太多时间.希望这篇文章能够帮助大家少走弯路~~ 1.下载我下载的是64位. 2.解压下载之后,我选 ...

  4. BZOJ3130 [Sdoi2013]费用流 【网络流 + 二分】

    题目 Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识. 最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每 ...

  5. TeraTerm设定(窗体大小,字体字号)保存为默认值

    Tera Term是一款很好的SSH工具,大家经常遇到一个头疼的问题,每次打开的时候,都要自己重新设置一遍Font. 介绍一下把自己喜欢的字体,设置好后,保存到默认配置中的方法. 设置窗体大小: 设置 ...

  6. hdu3038 How Many Answers Are Wrong

    TT and FF are ... friends. Uh... very very good friends -________-b FF is a bad boy, he is always wo ...

  7. mongodb的安装及环境配置

    一 下载 官网:https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.6.3-signed.msi 官网可能打不开, ...

  8. 【BZOJ1412】狼和羊的故事(最小割)

    题意:将一个由0,1,2构成的矩阵里的1与2全部分割最少需要选取多少条边 n,m<=100 思路:裸的最小割模型 相邻的格子连容量为1的边(其实可以少连很多遍,1与1,2与2之间的边是没有意义的 ...

  9. Scott Mitchell的ASP.NET2.0数据指南中文版索引

    原文发布时间为:2008-08-03 -- 来源于本人的百度文章 [由搬家工具导入] 原文http://www.cnblogs.com/ilovejolly/archive/2006/10/05/52 ...

  10. JavaScript 数组操作函数--转载+格式整理

    JavaScript 数组操作函数(部分)--转载+格式整理 今天看了一篇文章,主要讲的对常用的Js操作函数:push,pop,join,shift,unshift,slice,splice,conc ...