i2c驱动

访问i2c设备有以下几种方法:

一、在内核内核提供了i2c-dev驱动的前提下,用以下四种方法例化设备;然后用户直接通过访问/sys/bus/i2c/devices/i2c-0/0-0054/eeprom读写设备。

 

How to instantiate I2C devices ? 来自linux-2.6.35/Documentation/i2c/instantiating-devices

1、 在用户空间创建和删除i2c_device(参考内核帮助文档 instantiating-devices)

//linux-2.6.35/Documentation/i2c/instantiating-devices.....How to instantiate I2C devices.....Method 4: Instantiate from user-space

Example:
# echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-0/new_device  
# echo 0x50 > /sys/bus/i2c/devices/i2c-0/delete_device

  分析过设备模型的都知道,i2c-0 是我们上面设置的 dev_set_name(&adap->dev, "i2c-%d", adap->nr)new_device 就是它的一个属性了,这个属性在哪里?在i2c_adapter_type .

  Note:该方法实现的前提是把内核自带的i2c设备驱动和adapter驱动编入内核,只是没有在平台代码里添加i2c_board_info。

 

2、直接在平台代码里添加i2c_board_info;

//linux-2.6.35/Documentation/i2c/instantiating-devices.....How to instantiate I2C devices.....Method 1: Declare the I2C devices by bus number

  s5pc100为例,在arch/arm/mach-s5pc100.c中添加如下代码:

static struct i2c_board_info i2c_devs0[] __initdata = {
    {I2C_BOARD_INFO("lm75", 0x48),},
};

static void __init smdkc100_machine_init(void)
{
…
/* I2C */
    i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
…
}

Note:该方法实现的前提是把内核自带的i2c设备驱动和adapter驱动编入内核。

遇到的问题:在/dev和/sys下没有找到i2c总线(i2c-0,i2c-1)

原因:在调试的时候遇到没有将adapter(i2c_s3c2410)编译进内核

解决办法:

         修改kconfig:

                  在目录drivers/i2c/busses/Kconfig

                  修改:

                  config I2C_S3C2410

                  tristate "S3C2410 I2C Driver"

                  depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100

         配置内核:

                  Device Drivers

                          <*> I2C support  --->

                                   I2C Hardware Bus support  ---> 

                                            <*> S3C2410 I2C Driver 

前面两种方法都是在/sys/devices/platform/s3c2440-i2c.0/i2c-0/0-0048下创建设备,下面介绍一种在/dev/at24cxx创建设备(跟普通的字符设备一样)

 

3、直接在设备侧使用 i2c_new_device创建一个设备注册到 i2c_bus_type。 

#include <linux/kernel.h>  
#include <linux/module.h>  
#include <linux/platform_device.h>  
#include <linux/i2c.h>  
#include <linux/err.h>  
#include <linux/regmap.h>  
#include <linux/slab.h> 
  
static struct i2c_board_info at24cxx_info = {     
    I2C_BOARD_INFO("24c08", 0x50),  
};  
  
static struct i2c_client *at24cxx_client;  
  
static int at24cxx_dev_init(void)  
{  
    struct i2c_adapter *i2c_adap;  
    // 获取设备号为 0 的adpter ,也就是adapter->nr == 0  
    i2c_adap = i2c_get_adapter(0);  
    // 直接使用 i2c_new_device 创建 client 自动注册到i2c_bus_type 中去,client->name == "at24c08" ,client->addr = 0x50  
    at24cxx_client = i2c_new_device(i2c_adap, &at24cxx_info);  
    // 释放掉 adapter  
    i2c_put_adapter(i2c_adap);    
    return 0;  
}  
  
static void at24cxx_dev_exit(void)  
{  
    i2c_unregister_device(at24cxx_client);  
}  
  
module_init(at24cxx_dev_init);  
module_exit(at24cxx_dev_exit);  
MODULE_LICENSE("GPL");  

 

4、需要probe检测设备的情形(还未研究透)

//linux-2.6.35/Documentation/i2c/instantiating-devices.....How to instantiate I2C devices.....Method 3: Probe an I2C bus for certain devices

Sometimes you do not have enough information about an I2C device, not even
to call i2c_new_probed_device(). The typical case is hardware monitoring
chips on PC mainboards. There are several dozen models, which can live
at 25 different addresses. Given the huge number of mainboards out there,
it is next to impossible to build an exhaustive list of the hardware
monitoring chips being used. Fortunately, most of these chips have
manufacturer and device ID registers, so they can be identified by
probing.

In that case, I2C devices are neither declared nor instantiated
explicitly. Instead, i2c-core will probe for such devices as soon as their
drivers are loaded, and if any is found, an I2C device will be
instantiated automatically. In order to prevent any misbehavior of this
mechanism, the following restrictions apply:
* The I2C device driver must implement the detect() method, which
  identifies a supported device by reading from arbitrary registers.
* Only buses which are likely to have a supported device and agree to be
  probed, will be probed. For example this avoids probing for hardware
  monitoring chips on a TV adapter.

Example:
See lm90_driver and lm90_detect() in drivers/hwmon/lm90.c

 

二、内核没有提供相关设备的驱动,就需要按照普通字符设备编写i2c-dev的驱动;然后用户通过读写/dev/<filename>访问设备


参考:http://blog.csdn.net/lizuobin2/article/details/51694574 4、写设备驱动程序

以at24cxx为例编写i2c_device的驱动。

 

三、在用户空间通过操作i2c_bus实现对总线上设备的访问。

参考:<< F:\1303_farsight\1303 MR_PAN\项目\1209期项目\1209\第一组_毕业相关文档提交\高磊\驱动代码\my_lm75 >>

实例: 

/*i2c_dev.h*/
#ifndef _I2C_DEV_H_
#define _I2C_DEV_H_

#include <stdio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#define CHIP_ADDR 0X54
#endif

 

/* i2c_dev.c */

#include"i2c_dev.h"
int i2cdev_open(void)
{
    int fd;
  fd
= open("/dev/i2c-0",O_RDWR) if(fd < 0) { perror("open error"); exit(1); } return fd; } int i2cdev_read(int fd, char addr) { int ret; char data; struct i2c_rdwr_ioctl_data e2prom_data; e2prom_data.nmsgs=2; e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg)); if(!e2prom_data.msgs) { perror("malloc error"); exit(1); } ioctl(fd,I2C_TIMEOUT,1); ioctl(fd,I2C_RETRIES,2); usleep(100000); e2prom_data.nmsgs=2; (e2prom_data.msgs[0]).len=1; //e2prom 目标数据的地址 (e2prom_data.msgs[0]).addr=CHIP_ADDR; // e2prom 设备地址 (e2prom_data.msgs[0]).flags=0;//write (e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2); (e2prom_data.msgs[0]).buf[0]=addr;//e2prom数据地址 (e2prom_data.msgs[1]).len=2;//读出的数据 (e2prom_data.msgs[1]).addr=CHIP_ADDR;// e2prom 设备地址 (e2prom_data.msgs[1]).flags=I2C_M_RD;//read (e2prom_data.msgs[1]).buf=(unsigned char*)malloc(1);//存放返回值的地址。    memset((e2prom_data.msgs[1]).buf, 0, 1);
ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data); if(ret<0) { perror("ioctl error2"); }
  data = *((e2prom_data.msgs[1]).buf);
return data; }

int i2cdev_write(int fd, char addr, char val)
{
    int ret;
    char data;
    struct i2c_rdwr_ioctl_data e2prom_data;

    e2prom_data.nmsgs=1;
    e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));
    if(!e2prom_data.msgs)
    {
        perror("malloc error");
        exit(1);
    }

    ioctl(fd,I2C_TIMEOUT,1);
    ioctl(fd,I2C_RETRIES,2);
    usleep(100000);

    e2prom_data.nmsgs=1;
    (e2prom_data.msgs[0]).len=2; //e2prom 目标数据的地址
    (e2prom_data.msgs[0]).addr=CHIP_ADDR; // e2prom 设备地址
    (e2prom_data.msgs[0]).flags=0;//write
    (e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);
    (e2prom_data.msgs[0]).buf[0]=addr;//e2prom数据地址
   (e2prom_data.msgs[0]).buf[1]=val;
ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data); if(ret<0) { perror("ioctl error2"); }

}
void i2cdev_close(int fd) { close(fd); }

 

 

/*test.c*/
#include "i2c_dev.h"

int main()
{
    int fd;
    int data;
    while(1){
    fd=i2cdev_open();
    data = i2cdev_read(fd, 0x0);
    printf("data is %d\n",data);
    temp_close(fd);
    sleep(1);
    }
}

 

posted @ 2016-09-04 22:18  lilyhuang523  阅读(2131)  评论(0编辑  收藏  举报