1. 程式人生 > >Linux裝置驅動之3.4.2核心下的I2C驅動

Linux裝置驅動之3.4.2核心下的I2C驅動

  1. 框架
    1.1 硬體協議簡介
    1.2 驅動框架
    1.3 bus-drv-dev模型及寫程式
    a. 裝置的4種構建方法

詳情參照:linux-3.4.2\Documentation\i2c:instantiating-devices:
以下摘取部分

Method 1: Declare the I2C devices by bus number

Method 2: Instantiate the devices explicitly
static struct i2c_board_info sfe4001_hwmon_info = {
    I2C_BOARD_INFO("max6647"
, 0x4e), }; int sfe4001_init(struct efx_nic *efx) { (...) efx->board_info.hwmon_client = i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); (...) } static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) { (...
) struct i2c_adapter *i2c_adap; struct i2c_board_info i2c_info; (...) i2c_adap = i2c_get_adapter(2); memset(&i2c_info, 0, sizeof(struct i2c_board_info)); strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE); isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, normal_i2c, NULL
); i2c_put_adapter(i2c_adap); (...) } Method 3: Probe an I2C bus for certain devices Method 4: Instantiate from user-space Example: # echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device

對上面該Document文件進行解析:

a.1 定義一個i2c_board_info, 裡面有:名字, 裝置地址
然後i2c_register_board_info(busnum, …) (把它們放入__i2c_board_list連結串列)
list_add_tail(&devinfo->list, &__i2c_board_list);

連結串列何時使用:
i2c_register_adapter > i2c_scan_static_board_info > i2c_new_device

使用限制:必須在 i2c_register_adapter 之前 i2c_register_board_info
所以:不適合我們動態載入insmod

a.2 直接i2c_new_device, i2c_new_probed_device : probed:建立已經被列舉被識別的裝置!
a.2.1 i2c_new_device : 強制認為裝置肯定存在
a.2.2
i**2c_new_probed_device :對於”已經識別出來的裝置”(probed_device),才會建立(“new”)**
i2c_new_probed_device :對addr_list裡面的每一項呼叫probe函式,如果存在的話,才進行new_device
probe(adap, addr_list[i]) /* 確定裝置是否真實存在 */
info->addr = addr_list[i];/遍歷連結串列/
i2c_new_device(adap, info);

a.4 從使用者空間建立裝置
建立裝置
echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-0/new_device
導致i2c_new_device被呼叫

刪除裝置
echo 0x50 > /sys/class/i2c-adapter/i2c-0/delete_device
導致i2c_unregister_device

a.3
前面的3種方法都要事先確定介面卡(I2C匯流排,I2C控制器)
問1:如果我事先並不知道這個I2C裝置在哪個介面卡上,怎麼辦?
答1:去class表示的所有的介面卡上查詢
問2:有上一些I2C裝置的地址是一樣,怎麼繼續分配它是哪一款?
答2:用detect函式

static struct i2c_driver at24cxx_driver = {
    .class  = I2C_CLASS_HWMON,      /* 表示去哪些介面卡上找裝置 */
    .driver    = {
        .name    = "100ask",
        .owner    = THIS_MODULE,
    },
    .probe        = at24cxx_probe,
    .remove        = __devexit_p(at24cxx_remove),
    .id_table    = at24cxx_id_table,
    .detect     = at24cxx_detect,  /* 用這個函式來檢測裝置確實存在 */
    .address_list    = addr_list,   /* 這些裝置的地址 */
};

例如at24xx的addr_list
static const unsigned short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END };

解析:
去”class表示的這一類”I2C介面卡,用”detect函式”來確定能否找到”address_list裡的裝置”,
如果能找到就呼叫i2c_new_device來註冊i2c_client, 這會和i2c_driver的id_table比較,
如果匹配,呼叫probe

分析函式流程!
i2c_add_driver
i2c_register_driver
a. 將at24cxx_driver放入i2c_bus_type的drv連結串列
並且從dev連結串列裡取出能匹配的i2c_client並呼叫probe
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
driver_register

b. 對於每一個介面卡,呼叫__process_new_driver
對於每一個介面卡,呼叫它的函式確定address_list裡的裝置是否存在
如果存在,再呼叫detect進一步確定、設定,然後i2c_new_device

      /* Walk the adapters that are already present */
        i2c_for_each_dev(driver, __process_new_driver);
            __process_new_driver
                i2c_do_add_adapter
                    /* Detect supported devices on that bus, and instantiate them */
                    i2c_detect(adap, driver);
                        for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
                            err = i2c_detect_address(temp_client, driver);
                                         /* Make sure there is something at this address */
                                        /* 判斷這個裝置是否存在:簡單的發出S訊號確定有ACK */
                                        if (!i2c_default_probe(adapter, addr))
                                            return 0;

                                        memset(&info, 0, sizeof(struct i2c_board_info));
                                        info.addr = addr;   

                                        // 設定info.type
                                        err = driver->detect(temp_client, &info);

                                        i2c_new_device

附上方法三(即是a3中對應的)程式碼:

at24cxx_drv.c:

#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 int __devinit at24cxx_probe(struct i2c_client *client,
                  const struct i2c_device_id *id)
{
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}

static int __devexit at24cxx_remove(struct i2c_client *client)
{
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}

static const struct i2c_device_id at24cxx_id_table[] = {
    { "at24c08", 0 },
    {}
};

static int at24cxx_detect(struct i2c_client *client,
               struct i2c_board_info *info)
{
    /* 能執行到這裡, 表示該addr的裝置是存在的
     * 但是有些裝置單憑地址無法分辨(A晶片的地址是0x50, B晶片的地址也是0x50)
     * 還需要進一步讀寫I2C裝置來分辨是哪款晶片
     * detect就是用來進一步分辨這個晶片是哪一款,並且設定info->type
     */

    printk("at24cxx_detect : addr = 0x%x\n", client->addr);

    /* 進一步判斷是哪一款 */

    strlcpy(info->type, "at24c08", I2C_NAME_SIZE);
    return 0;
}

static const unsigned short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END };

/* 1. 分配/設定i2c_driver */
static struct i2c_driver at24cxx_driver = {
    .class  = I2C_CLASS_HWMON, /* 表示去哪些介面卡上找裝置 */
    .driver    = {
        .name    = "100ask",
        .owner    = THIS_MODULE,
    },
    .probe        = at24cxx_probe,
    .remove        = __devexit_p(at24cxx_remove),
    .id_table    = at24cxx_id_table,
    .detect     = at24cxx_detect,  /* 用這個函式來檢測裝置確實存在 */
    .address_list    = addr_list,   /* 這些裝置的地址 */
};

static int at24cxx_drv_init(void)
{
    /* 2. 註冊i2c_driver */
    i2c_add_driver(&at24cxx_driver);

    return 0;
}

static void at24cxx_drv_exit(void)
{
    i2c_del_driver(&at24cxx_driver);
}


module_init(at24cxx_drv_init);
module_exit(at24cxx_drv_exit);
MODULE_LICENSE("GPL");

匯流排:
1、SMBUS:system manager bus
2、 i2c_trasfer

 系統推薦我們用SMBUS,看下官方提供的Doucument
SMBus Protocol Summary
======================

The following is a summary of the SMBus protocol. It applies to
all revisions of the protocol (1.0, 1.1, and 2.0).
Certain protocol features which are not supported by
this package are briefly described at the end of this document.

Some adapters understand only the SMBus (System Management Bus) protocol,
which is a subset from the I2C protocol. Fortunately, many devices use
only the same subset, which makes it possible to put them on an SMBus.

If you write a driver for some I2C device, please try to use the SMBus
commands if at all possible (if the device uses only that subset of the
I2C protocol). This makes it possible to use the device driver on both
SMBus adapters and I2C adapters (the SMBus command set is automatically
translated to I2C on I2C adapters, but plain I2C commands can not be
handled at all on most pure SMBus adapters).

Below is a list of SMBus protocol operations, and the functions executing
them.  Note that the names used in the SMBus protocol specifications usually
don't match these function names.  For some of the operations which pass a
single data byte, the functions using SMBus protocol operation names execute
a different protocol operation entirely.


Key to symbols
==============

S     (1 bit) : Start bit
P     (1 bit) : Stop bit
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
A, NA (1 bit) : Accept and reverse accept bit. 
Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to 
                get a 10 bit I2C address.
Comm  (8 bits): Command byte, a data byte which often selects a register on
                the device.
Data  (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
                for 16 bit data.
Count (8 bits): A data byte containing the length of a block operation.

[..]: Data sent by I2C device, as opposed to data sent by the host adapter.


SMBus Quick Command
===================

This sends a single bit to the device, at the place of the Rd/Wr bit.

A Addr Rd/Wr [A] P


SMBus Receive Byte:  i2c_smbus_read_byte()
==========================================

This reads a single byte from a device, without specifying a device
register. Some devices are so simple that this interface is enough; for
others, it is a shorthand if you want to read the same register as in
the previous SMBus command.

S Addr Rd [A] [Data] NA P


SMBus Send Byte:  i2c_smbus_write_byte()
========================================

This operation is the reverse of Receive Byte: it sends a single byte
to a device.  See Receive Byte for more information.

S Addr Wr [A] Data [A] P


SMBus Read Byte:  i2c_smbus_read_byte_data()
============================================

This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte.

S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P


SMBus Read Word:  i2c_smbus_read_word_data()
============================================

This operation is very like Read Byte; again, data is read from a
device, from a designated register that is specified through the Comm
byte. But this time, the data is a complete word (16 bits).

S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P

Note the convenience function i2c_smbus_read_word_swapped is
available for reads where the two data bytes are the other way
around (not SMBus compliant, but very popular.)


SMBus Write Byte:  i2c_smbus_write_byte_data()
==============================================

This writes a single byte to a device, to a designated register. The
register is specified through the Comm byte. This is the opposite of
the Read Byte operation.

S Addr Wr [A] Comm [A] Data [A] P


SMBus Write Word:  i2c_smbus_write_word_data()
==============================================

This is the opposite of the Read Word operation. 16 bits
of data is written to a device, to the designated register that is
specified through the Comm byte. 

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P

Note the convenience function i2c_smbus_write_word_swapped is
available for writes where the two data bytes are the other way
around (not SMBus compliant, but very popular.)


SMBus Process Call:  i2c_smbus_process_call()
=============================================

This command selects a device register (through the Comm byte), sends
16 bits of data to it, and reads 16 bits of data in return.

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] 
                             S Addr Rd [A] [DataLow] A [DataHigh] NA P


SMBus Block Read:  i2c_smbus_read_block_data()
==============================================

This command reads a block of up to 32 bytes from a device, from a 
designated register that is specified through the Comm byte. The amount
of data is specified by the device in the Count byte.

S Addr Wr [A] Comm [A] 
           S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P


SMBus Block Write:  i2c_smbus_write_block_data()
================================================

The opposite of the Block Read command, this writes up to 32 bytes to 
a device, to a designated register that is specified through the
Comm byte. The amount of data is specified in the Count byte.

S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P


SMBus Block Write - Block Read Process Call
===========================================

SMBus Block Write - Block Read Process Call was introduced in
Revision 2.0 of the specification.

This command selects a device register (through the Comm byte), sends
1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return.

S Addr Wr [A] Comm [A] Count [A] Data [A] ...
                             S Addr Rd [A] [Count] A [Data] ... A P


SMBus Host Notify
=================

This command is sent from a SMBus device acting as a master to the
SMBus host acting as a slave.
It is the same form as Write Word, with the command code replaced by the
alerting device's address.

[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P]


Packet Error Checking (PEC)
===========================

Packet Error Checking was introduced in Revision 1.1 of the specification.

PEC adds a CRC-8 error-checking byte to transfers using it, immediately
before the terminating STOP.


Address Resolution Protocol (ARP)
=================================

The Address Resolution Protocol was introduced in Revision 2.0 of
the specification. It is a higher-layer protocol which uses the
messages above.

ARP adds device enumeration and dynamic address assignment to
the protocol. All ARP communications use slave address 0x61 and
require PEC checksums.


SMBus Alert
===========

SMBus Alert was introduced in Revision 1.0 of the specification.

The SMBus alert protocol allows several SMBus slave devices to share a
single interrupt pin on the SMBus master, while still allowing the master
to know which slave triggered the interrupt.

This is implemented the following way in the Linux kernel:
* I2C bus drivers which support SMBus alert should call
  i2c_setup_smbus_alert() to setup SMBus alert support.
* I2C drivers for devices which can trigger SMBus alerts should implement
  the optional alert() callback.


I2C Block Transactions
======================

The following I2C block transactions are supported by the
SMBus layer and are described here for completeness.
They are *NOT* defined by the SMBus specification.

I2C block transactions do not limit the number of bytes transferred
but the SMBus layer places a limit of 32 bytes.


I2C Block Read:  i2c_smbus_read_i2c_block_data()
================================================

This command reads a block of bytes from a device, from a 
designated register that is specified through the Comm byte.

S Addr Wr [A] Comm [A] 
           S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P


I2C Block Read (2 Comm bytes)
=============================

This command reads a block of bytes from a device, from a 
designated register that is specified through the two Comm bytes.

S Addr Wr [A] Comm1 [A] Comm2 [A] 
           S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P


I2C Block Write:  i2c_smbus_write_i2c_block_data()
==================================================

The opposite of the Block Read command, this writes bytes to 
a device, to a designated register that is specified through the
Comm byte. Note that command lengths of 0, 2, or more bytes are
supported as they are indistinguishable from data.

S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P

b. 驅動的寫法

2、 完善裝置驅動程式

at24cxx_dev.c:

#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("at24c08", 0x50),
};

static struct i2c_client *at24cxx_client;

static int at24cxx_dev_init(void)
{
    struct i2c_adapter *i2c_adap;

    i2c_adap = i2c_get_adapter(0);
    at24cxx_client = i2c_new_device(i2c_adap, &at24cxx_info);
    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");


at24cxx_drv.c:

#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>
#include <linux/fs.h>
#include <asm/uaccess.h>


static int major;
static struct class *class;
static struct i2c_client *at24cxx_client;

/* 傳入: buf[0] : addr
 * 輸出: buf[0] : data
 */
static ssize_t at24cxx_read(struct file * file, char __user *buf, size_t count, loff_t *off)
{
    unsigned char addr, data;

    copy_from_user(&addr, buf, 1);
    data = i2c_smbus_read_byte_data(at24cxx_client, addr);
    copy_to_user(buf, &data, 1);
    return 1;
}

/* buf[0] : addr
 * buf[1] : data
 */
static ssize_t at24cxx_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
    unsigned char ker_buf[2];
    unsigned char addr, data;

    copy_from_user(ker_buf, buf, 2);
    addr = ker_buf[0];
    data = ker_buf[1];

    printk("addr = 0x%02x, data = 0x%02x\n", addr, data);

    if (!i2c_smbus_write_byte_data(at24cxx_client, addr, data))
        return 2;
    else
        return -EIO;   
}

static struct file_operations at24cxx_fops = {
    .owner = THIS_MODULE,
    .read  = at24cxx_read,
    .write = at24cxx_write,
};

static int __devinit at24cxx_probe(struct i2c_client *client,
                  const struct i2c_device_id *id)
{
    at24cxx_client = client;

    //printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    major = register_chrdev(0, "at24cxx", &at24cxx_fops);
    class = class_create(THIS_MODULE, "at24cxx");
    device_create(class, NULL, MKDEV(major, 0), NULL, "at24cxx"); /* /dev/at24cxx */

    return 0;
}

static int __devexit at24cxx_remove(struct i2c_client *client)
{
    //printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    device_destroy(class, MKDEV(major, 0));
    class_destroy(class);
    unregister_chrdev(major, "at24cxx");

    return 0;
}

static const struct i2c_device_id at24cxx_id_table[] = {
    { "at24c08", 0 },
    {}
};


/* 1. 分配/設定i2c_driver */
static struct i2c_driver at24cxx_driver = {
    .driver    = {
        .name    = "100ask",
        .owner    = THIS_MODULE,
    },
    .probe        = at24cxx_probe,
    .remove        = __devexit_p(at24cxx_remove),
    .id_table    = at24cxx_id_table,
};

static int at24cxx_drv_init(void)
{
    /* 2. 註冊i2c_driver */
    i2c_add_driver(&at24cxx_driver);

    return 0;
}

static void at24cxx_drv_exit(void)
{
    i2c_del_driver(&at24cxx_driver);
}


module_init(at24cxx_drv_init);
module_exit(at24cxx_drv_exit);
MODULE_LICENSE("GPL");


i2c_test.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


/* i2c_test r addr
 * i2c_test w addr val
 */

void print_usage(char *file)
{
    printf("%s r addr\n", file);
    printf("%s w addr val\n", file);
}

int main(int argc, char **argv)
{
    int fd;
    unsigned char buf[2];

    if ((argc != 3) && (argc != 4))
    {
        print_usage(argv[0]);
        return -1;
    }

    fd = open("/dev/at24cxx", O_RDWR);
    if (fd < 0)
    {
        printf("can't open /dev/at24cxx\n");
        return -1;
    }

    if (strcmp(argv[1], "r") == 0)
    {
        buf[0] = strtoul(argv[2], NULL, 0);
        read(fd, buf, 1);
        printf("data: %c, %d, 0x%2x\n", buf[0], buf[0], buf[0]);
    }
    else if ((strcmp(argv[1], "w") == 0) && (argc == 4))
    {
        buf[0] = strtoul(argv[2], NULL, 0);
        buf[1] = strtoul(argv[3], NULL, 0);
        if (write(fd, buf, 2) != 2)
            printf("write err, addr = 0x%02x, data = 0x%02x\n", buf[0], buf[1]);
    }
    else
    {
        print_usage(argv[0]);
        return -1;
    }

    return 0;
}

三、不自己寫驅動,直接訪問
參考文件:dev-interface

Usually, i2c devices are controlled by a kernel driver. But it is also
possible to access all devices on an adapter from userspace, through
the /dev interface. You need to load module i2c-dev for this.

Each registered i2c adapter gets a number, counting from 0. You can
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
i2c adapters present on your system at a given time. i2cdetect is part of
the i2c-tools package.

I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as 
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
i2c-10, ...). All 256 minor device numbers are reserved for i2c.


C example
=========

So let's say you want to access an i2c adapter from a C program. The
first thing to do is "#include <linux/i2c-dev.h>". Please note that
there are two files named "i2c-dev.h" out there, one is distributed
with the Linux kernel and is meant to be included from kernel
driver code, the other one is distributed with i2c-tools and is
meant to be included from user-space programs. You obviously want
the second one here.

Now, you have to decide which adapter you want to access. You should
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
Adapter numbers are assigned somewhat dynamically, so you can not
assume much about them. They can even change from one boot to the next.

Next thing, open the device file, as follows:

  int file;
  int adapter_nr = 2; /* probably dynamically determined */
  char filename[20];

  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
  file = open(filename, O_RDWR);
  if (file < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

When you have opened the device, you must specify with what device
address you want to communicate:

  int addr = 0x40; /* The I2C address */

  if (ioctl(file, I2C_SLAVE, addr) < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

Well, you are all set up now. You can now use SMBus commands or plain
I2C to communicate with your device. SMBus commands are preferred if
the device supports them. Both are illustrated below.

  __u8 register = 0x10; /* Device register to access */
  __s32 res;
  char buf[10];

  /* Using SMBus commands */
  res = i2c_smbus_read_word_data(file, register);
  if (res < 0) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* res contains the read word */
  }

  /* Using I2C Write, equivalent of 
     i2c_smbus_write_word_data(file, register, 0x6543) */
  buf[0] = register;
  buf[1] = 0x43;
  buf[2] = 0x65;
  if (write(file, buf, 3) ! =3) {
    /* ERROR HANDLING: i2c transaction failed */
  }

  /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
  if (read(file, buf, 1) != 1) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* buf[0] contains the read byte */
  }

Note that only a subset of the I2C and SMBus protocols can be achieved by
the means of read() and write() calls. In particular, so-called combined
transactions (mixing read and write messages in the same transaction)
aren't supported. For this reason, this interface is almost never used by
user-space programs.

IMPORTANT: because of the use of inline functions, you *have* to use
'-O' or some variation when you compile your program!


Full interface description
==========================

The following IOCTLs are defined:

ioctl(file, I2C_SLAVE, long addr)
  Change slave address. The address is passed in the 7 lower bits of the
  argument (except for 10 bit addresses, passed in the 10 lower bits in this
  case).

ioctl(file, I2C_TENBIT, long select)
  Selects ten bit addresses if select not equals 0, selects normal 7 bit
  addresses if select equals 0. Default 0.  This request is only valid
  if the adapter has I2C_FUNC_10BIT_ADDR.

ioctl(file, I2C_PEC, long select)
  Selects SMBus PEC (packet error checking) generation and verification
  if select not equals 0, disables if select equals 0. Default 0.
  Used only for SMBus transactions.  This request only has an effect if the
  the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
  doesn't have any effect.

ioctl(file, I2C_FUNCS, unsigned long *funcs)
  Gets the adapter functionality and puts it in *funcs.

ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
  Do combined read/write transaction without stop in between.
  Only valid if the adapter has I2C_FUNC_I2C.  The argument is
  a pointer to a

  struct i2c_rdwr_ioctl_data {
      struct i2c_msg *msgs;  /* ptr to array of simple messages */
      int nmsgs;             /* number of messages to exchange */
  }

  The msgs[] themselves contain further pointers into data buffers.
  The function will write or read data to or from that buffers depending
  on whether the I2C_M_RD flag is set in a particular message or not.
  The slave address and whether to use ten bit address mode has to be
  set in each message, overriding the values set with the above ioctl's.

ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
  Not meant to be called  directly; instead, use the access functions
  below.

You can do plain i2c transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
ioctl I2C_SLAVE before you try to access the device.

You can do SMBus level transactions (see documentation file smbus-protocol 
for details) through the following functions:
  __s32 i2c_smbus_write_quick(int file, __u8 value);
  __s32 i2c_smbus_read_byte(int file);
  __s32 i2c_smbus_write_byte(int file, __u8 value);
  __s32 i2c_smbus_read_byte_data(int file, __u8 command);
  __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
  __s32 i2c_smbus_read_word_data(int file, __u8 command);
  __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
  __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, 
                                   __u8 *values);
All these transactions return -1 on failure; you can read errno to see
what happened. The 'write' transactions return 0 on success; the
'read' transactions return the read value, except for read_block, which
returns the number of values read. The block buffers need not be longer
than 32 bytes.

The above functions are all inline functions, that resolve to calls to
the i2c_smbus_access function, that on its turn calls a specific ioctl
with the data in a specific format. Read the source code if you
want to know what happens behind the screens.


Implementation details
======================

For the interested, here's the code flow which happens inside the kernel
when you use the /dev interface to I2C:

1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
section "C example" above.

2* These open() and ioctl() calls are handled by the i2c-dev kernel
driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
respectively. You can think of i2c-dev as a generic I2C chip driver
that can be programmed from user-space.

3* Some ioctl() calls are for administrative tasks and are handled by
i2c-dev directly. Examples include I2C_SLAVE (set the address of the
device you want to access) and I2C_PEC (enable or disable SMBus error
checking on future transactions.)

4* Other ioctl() calls are converted to