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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM