Linux 內核I2C總線架構

總線是將設備與驅動聯繫在一起的紐帶。
如果一個設備與驅動彼此綁在了一起,通過sys目錄下的文件信息能看出其綁定的驅動/設備對象。
如:

~# ls /sys/bus/i2c/drivers/ad-7441/ -l
lrwxrwxrwx    1 root     root             0 Jan  1 00:07 2-0070 -> ../../../../devices/platform/hisi_i2c.2/i2c-2/2-0070
--w-------    1 root     root          4096 Jan  1 00:07 bind
--w-------    1 root     root          4096 Jan  1 00:07 uevent
--w-------    1 root     root          4096 Jan  1 00:07 unbind

可以看出i2c總線上的名字爲ad-7441的i2c_driver找到了其綁定的設備。
同樣有:

/sys/devices/platform/hisi_i2c.2/i2c-2# ls 2-0070/ -l
lrwxrwxrwx    1 root     root             0 Jan  1 00:06 driver -> ../../../../../bus/i2c/drivers/ad-7441
-r--r--r--    1 root     root          4096 Jan  1 00:06 modalias
-r--r--r--    1 root     root          4096 Jan  1 00:06 name
drwxr-xr-x    2 root     root             0 Jan  1 00:06 power
lrwxrwxrwx    1 root     root             0 Jan  1 00:06 subsystem -> ../../../../../bus/i2c
-rw-r--r--    1 root     root          4096 Jan  1 00:06 uevent
/sys/devices/platform/hisi_i2c.2/i2c-2# cat  2-0082/name 
adv8200

由於系統中沒有i2c_add_driver 成員 id_table的name爲adv8200的i2c_driver,所以,這裏的2-0082是找不到自己的另一半的。
相反,系統中定義了:

const static struct i2c_device_id slaveid[]={
            {.name="adv7441"},
            {.name="GS2970"},

};
static struct i2c_driver adv7441_driver={
    .probe=adv7441_probe,
    .id_table=slaveid,
    .driver = {
            .name   = "ad-7441",
            .owner  = THIS_MODULE,
    },
};
ret=i2c_add_driver(&adv7441_driver);

就因爲這樣,ad-7441找到了driver,而8200卻找不到driver。
通常情況下,在一個已經配置了i2c_adpter設備的系統中,如果要在內核中添加一個i2c從設備的驅動。最常用的做法是:
1. 定義 i2c_board_info,並執行i2c_register_board_info(int busnum,
struct i2c_board_info const *info, unsigned len)。該函數會申請分配i2c_board_info
並添加到__i2c_board_list爲頭的鏈表中。

struct i2c_board_info {
    char        type[I2C_NAME_SIZE];
    unsigned short  flags;
    unsigned short  addr;
    void        *platform_data;
    struct dev_archdata *archdata;
    struct device_node *of_node;
    int     irq;
};
/*  
 * I2C  slave devices 
 */
static struct i2c_board_info __initdata i2c_devs[] = {
        { I2C_BOARD_INFO("testA8", 0xA8), },
        { I2C_BOARD_INFO("adv7441", 0x70), },
        { I2C_BOARD_INFO("adv8200", 0x82), },
};
i2c_register_board_info(2, i2c_devs, ARRAY_SIZE(i2c_devs))

2.定義i2c_driver結構體,由於i2c_bus_type的match函數是根據id_table來判斷是否存在另一半的,因此i2c_driver中要定義合適的id_table字段。並執行i2c_add_driver把driver添加到i2c總線上,還可以定義probe函數,在probe函數中對i2c設備進行配置。。如:

static struct i2c_driver ds1307_driver = {
    .driver = {
        .name   = "rtc-ds1307",
        .owner  = THIS_MODULE,
    },
    .probe      = ds1307_probe,
    .remove     = __devexit_p(ds1307_remove),
    .id_table   = ds1307_id,
};
static const struct i2c_device_id ds1307_id[] = {
    { "ds1307", ds_1307 },
    { "ds1337", ds_1337 },
    { "ds1338", ds_1338 },
    { "ds1339", ds_1339 },
    { "ds1388", ds_1388 },
    { "ds1340", ds_1340 },
    { "ds3231", ds_3231 },
    { "m41t00", m41t00 },
    { "rx8025", rx_8025 },
    { }
};
const static struct i2c_device_id slaveid[]={
            {.name="adv7441"},
            {.name="GS2970"},

};
static struct i2c_driver adv7441_driver={
    .probe=adv7441_probe,
    .id_table=slaveid,
    .driver = {
            .name   = "ad-7441",
            .owner  = THIS_MODULE,
    },
};

那麼i2c_register_driver都做了哪些操作呢?
i2c_register_driver中的i2c_driver參數,如果i2c_driver參數定義了address_list且地址探測成功,則會自動調用i2c_new_device來創建設備。
如:

/* This is the driver that will be inserted */
static struct i2c_driver ads7828_driver = {
    .class = I2C_CLASS_HWMON,
    .driver = {
        .name = "ads7828",
    },
    .probe = ads7828_probe,
    .remove = ads7828_remove,
    .id_table = ads7828_id,
    .detect = ads7828_detect,
    .address_list = normal_i2c,
};
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,I2C_CLIENT_END };
    #define I2C_CLIENT_END      0xfffeU

跟蹤內核源碼,看i2c_register_driver的執行流程:

i2c_register_driver--》  i2c_for_each_dev(driver, __process_new_driver);---》i2c_do_add_adapter(data, to_i2c_adapter(dev));---》i2c_detect(adap, driver);---》  for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
        dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
            "addr 0x%02x\n", adap_id, address_list[i]);
        temp_client->addr = address_list[i];
        err = i2c_detect_address(temp_client, driver);
        if (unlikely(err))
            break;
    }

static int i2c_detect_address(struct i2c_client *temp_client,
                  struct i2c_driver *driver){

    if (info.type[0] == '\0') {//i2c_board_info的type字段不爲空
        dev_err(&adapter->dev, "%s detection function provided "
            "no name for 0x%x\n", driver->driver.name,
            addr);
    } else {
        struct i2c_client *client;

        /* Detection succeeded, instantiate the device */
        dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
            info.type, info.addr);
        client = i2c_new_device(adapter, &info);
        if (client)
            list_add_tail(&client->detected, &driver->clients);
        else
            dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
                info.type, info.addr);
    }

}
另外在i2c_register_adapter中執行的是
    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);

    一個是__process_new_driver,一個是__process_new_adapter,兩個都執行了i2c_detect--》i2c_detect_address---》i2c_new_device。i2c_new_device中會給i2c_client的adpter成員賦值,然後會執行device_register,如果match函數返回真,則會執行i2c_device_probe。
    不同的地方是__process_new_adapter執行的是 bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);遍歷i2c_bus上的所有driver。
    而i2c_register_driver用的是 i2c_for_each_dev(driver, __process_new_driver);---》bus_for_each_dev,遍歷的是i2c_bus上的所有device的時候,可以根據device得到adpter,因爲i2c_adapter中有device dev成員。通過#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
可以找到對應的adapter,然後adapter就可以作爲i2c_detect的參數傳進去。


    struct bus_type i2c_bus_type = {
    .name       = "i2c",
    .match      = i2c_device_match,
    .probe      = i2c_device_probe,
    .remove     = i2c_device_remove,
    .shutdown   = i2c_device_shutdown,
    .pm     = &i2c_device_pm_ops,
};
    static int i2c_device_probe(struct device *dev)
{
    struct i2c_client   *client = i2c_verify_client(dev);
    struct i2c_driver   *driver;
    int status;

    if (!client)
        return 0;

    driver = to_i2c_driver(dev->driver);
    if (!driver->probe || !driver->id_table)
        return -ENODEV;
    client->driver = driver;
    }
    由此可見,在i2c_new_device的過程中,首選給client賦adapter,如果批評成功,調用了i2c_bus_type的probe函數後,又會給i2c_client賦i2c_driver。i2c_client的driver和adapter成員都會得到正確的賦值。

這說明在註冊i2c_driver的時候,也可以自動的創建設備。
但不是必須這樣自動創建設備的,有的i2c_driver中沒有定義address_list也沒有自定義attach函數,那麼就不會自動創建i2c_device.

如果不在內核裏做的話,可以實現i2c-dev.c的fops,在應用層調用read、write、ioctl、open系統調用來配置i2c設備。
看了上面的內容,你會覺得太表面化了,或者是心裏沒底,爲什麼這樣做就可以呢。下面就來解釋一下!

i2c總線結構可以分爲3層:
1. i2c 核心層,主要是i2c-core.c,提供了i2c設備、驅動的註冊、註銷函數。I2C 通信方法(即“ algorithm”)上層的、與具體適配器無關的代碼以及探測設備、檢測設備地址的上層代碼等。
2. i2c設備層。這裏說的設備包括“主設備從設備”,主設備是指i2c適配器,一般是集成到CPU的i2c模塊,也可以是GPIO模擬的i2c模塊。從設備是指我們的板子上用的支持i2c總線的芯片,如RTC、AD、E2PROM等。
3. I2C設備驅動層,驅動是指從設備的設備。主要工作是填充I2c_driver。
我覺得上面的分層比較好理解。有的書上分三層是: 核心層、總線層、設備驅動層。其中總線層是適配器端完成的,而設備驅動層是I2C硬件體系結構中設備端的實現的,主要是填充i2c_client和driver。
這樣理解也行。可能是我對系統認識的不夠深,仍然覺得我自己的理解比較通俗。

一個常識性的知識,就是當device_add或者driver_add的時候,都會把device或者driver添加到bus的 struct subsys_private *p;成員指向的對應鏈表頭中,然後根據總線註冊的時候是否允許drivers_autoprobe,來進行探測。探測的時候會根據總線的match函數返回結果來決定是否要綁定dev和driver。那麼我們來看一下i2c_bus_type的註冊後是否允許drivers_autoprobe.

struct subsys_private {
    struct kset subsys;
    struct kset *devices_kset;
    struct list_head interfaces;
    struct mutex mutex;

    struct kset *drivers_kset;
    struct klist klist_devices;//添加到總線上的設備鏈表
    struct klist klist_drivers;//添加到總線上的驅動鏈表
    struct blocking_notifier_head bus_notifier;
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus;

    struct kset glue_dirs;
    struct class *class;
};
static int __init i2c_init(void)
{
    int retval;

    retval = bus_register(&i2c_bus_type);
    if (retval)
        return retval;
}
int __bus_register(struct bus_type *bus, struct lock_class_key *key)
{
    priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    priv->bus = bus;
    bus->p = priv;

    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
    if (retval)
        goto out;

    priv->subsys.kobj.kset = bus_kset;
    priv->subsys.kobj.ktype = &bus_ktype;
    **priv->drivers_autoprobe = 1;**

    retval = kset_register(&priv->subsys);
}

很明顯i2c_bus_type.p->drivers_autoprobe 是爲1的。因此在添加i2c設備和i2c驅動的時候,會自動匹配另一半。而總線匹配條件一般是總線的match成員函數返回的。那麼需要分析一下i2c總線的match函數:

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
    struct i2c_client   *client = i2c_verify_client(dev);
    struct i2c_driver   *driver;

    if (!client)
        return 0;

    /* Attempt an OF style match */
    if (of_driver_match_device(dev, drv))
        return 1;

    driver = to_i2c_driver(drv);
    /* match on an id table if there is one */
    if (driver->id_table)
        return i2c_match_id(driver->id_table, client) != NULL;

    return 0;
}
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
                        const struct i2c_client *client)
{
    while (id->name[0]) {
        if (strcmp(client->name, id->name) == 0)
            return id;
        id++;
    }
    return NULL;
}
struct bus_type i2c_bus_type = {
    .name       = "i2c",
    .match      = i2c_device_match,
    .probe      = i2c_device_probe,
    .remove     = i2c_device_remove,
    .shutdown   = i2c_device_shutdown,
    .pm     = &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);

i2c_driver的id_table裏的name字段與client字段相同則返回真進行匹配。而clientd的name是從哪裏來的呢?是在i2c_new_devie(adpter)的時候給賦值的。而i2c_new_device。如果執行了i2c_register_board_info,那麼就會調用到i2c_scan_static_board_info。i2c_scan_static_board_info在掃描過程中,會嘗試執行i2c_new_device進行匹配。匹配成功了設備與驅動就會綁定在一起。

在static int i2c_register_adapter(struct i2c_adapter *adap)中有

static int i2c_register_adapter(struct i2c_adapter *adap){
    dev_set_name(&adap->dev, "i2c-%d", adap->nr);//i2c-012
    adap->dev.bus = &i2c_bus_type;
    adap->dev.type = &i2c_adapter_type;
    res = device_register(&adap->dev);
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);

    /* Notify drivers */
    mutex_lock(&core_lock);
    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
    mutex_unlock(&core_lock);

    }
static int __process_new_adapter(struct device_driver *d, void *data)
{
    return i2c_do_add_adapter(to_i2c_driver(d), data);
}
static int i2c_do_add_adapter(struct i2c_driver *driver,
                  struct i2c_adapter *adap)
{
    /* Detect supported devices on that bus, and instantiate them */
    i2c_detect(adap, driver);

    /* Let legacy drivers scan this bus for matching devices */
    if (driver->attach_adapter) {
        dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
             driver->driver.name);
        dev_warn(&adap->dev, "Please use another way to instantiate "
             "your i2c_client\n");
        /* We ignore the return code; if it fails, too bad */
        driver->attach_adapter(adap);
    }
    return 0;
}
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{
    const unsigned short *address_list;
    struct i2c_client *temp_client;
    int i, err = 0;
    int adap_id = i2c_adapter_id(adapter);

    address_list = driver->address_list;
    if (!driver->detect || !address_list)
        return 0;

    /* Stop here if the classes do not match */
    if (!(adapter->class & driver->class))
        return 0;

    /* Set up a temporary client to help detect callback */
    temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
    if (!temp_client)
        return -ENOMEM;
    temp_client->adapter = adapter;

    for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
        dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
            "addr 0x%02x\n", adap_id, address_list[i]);
        temp_client->addr = address_list[i];
        err = i2c_detect_address(temp_client, driver);
        if (unlikely(err))
            break;
    }

    kfree(temp_client);
    return err;
}
static int i2c_detect_address(struct i2c_client *temp_client,
                  struct i2c_driver *driver)
{
    struct i2c_board_info info;
    struct i2c_adapter *adapter = temp_client->adapter;
    int addr = temp_client->addr;
    int err;

    /* Make sure the address is valid */
    err = i2c_check_addr_validity(addr);
    if (err) {
        dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
             addr);
        return err;
    }

    /* Skip if already in use */
    if (i2c_check_addr_busy(adapter, addr))
        return 0;

    /* Make sure there is something at this address */
    if (!i2c_default_probe(adapter, addr))
        return 0;

    /* Finally call the custom detection function */
    memset(&info, 0, sizeof(struct i2c_board_info));
    info.addr = addr;
    err = driver->detect(temp_client, &info);
    if (err) {
        /* -ENODEV is returned if the detection fails. We catch it
           here as this isn't an error. */
        return err == -ENODEV ? 0 : err;
    }

    /* Consistency check */
    if (info.type[0] == '\0') {
        dev_err(&adapter->dev, "%s detection function provided "
            "no name for 0x%x\n", driver->driver.name,
            addr);
    } else {
        struct i2c_client *client;

        /* Detection succeeded, instantiate the device */
        dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
            info.type, info.addr);
        client = i2c_new_device(adapter, &info);
        if (client)
            list_add_tail(&client->detected, &driver->clients);
        else
            dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
                info.type, info.addr);
    }
    return 0;
}

static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
    struct i2c_devinfo  *devinfo;

    down_read(&__i2c_board_lock);
    list_for_each_entry(devinfo, &__i2c_board_list, list) {
        if (devinfo->busnum == adapter->nr
                && !i2c_new_device(adapter,
                        &devinfo->board_info))
            dev_err(&adapter->dev,
                "Can't create device at 0x%02x\n",
                devinfo->board_info.addr);
    }
    up_read(&__i2c_board_lock);
}
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
    struct i2c_client   *client;
    int         status;

    client = kzalloc(sizeof *client, GFP_KERNEL);
    if (!client)
        return NULL;

    client->adapter = adap;

    client->dev.platform_data = info->platform_data;

    if (info->archdata)
        client->dev.archdata = *info->archdata;

    client->flags = info->flags;
    client->addr = info->addr;
    client->irq = info->irq;

    **strlcpy(client->name, info->type, sizeof(client->name));**

    /* Check for address validity */
    status = i2c_check_client_addr_validity(client);
    if (status) {
        dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
            client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
        goto out_err_silent;
    }

    /* Check for address business */
    status = i2c_check_addr_busy(adap, client->addr);
    if (status)
        goto out_err;

    client->dev.parent = &client->adapter->dev;
    client->dev.bus = &i2c_bus_type;
    client->dev.type = &i2c_client_type;
    client->dev.of_node = info->of_node;

    /* For 10-bit clients, add an arbitrary offset to avoid collisions */
    dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
             client->addr | ((client->flags & I2C_CLIENT_TEN)
                     ? 0xa000 : 0));
    status = device_register(&client->dev);
    if (status)
        goto out_err;

    dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
        client->name, dev_name(&client->dev));

    return client;

out_err:
    dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
        "(%d)\n", client->name, client->addr, status);
out_err_silent:
    kfree(client);
    return NULL;
}

如果內核啓動過程中沒有執行i2c_register_board_info,那麼__i2c_first_dynamic_bus_num的值就爲0,是不會執行i2c_scan_static_board_info的。
但是仍然可以在系統起來後,以模塊的形式調用i2c_new_device。如:

static struct i2c_board_info hi_info = {
     I2C_BOARD_INFO("sensor_i2c", 0x6c),
};
static int hi_dev_init(void)
{
    struct i2c_adapter *i2c_adap;

    // use i2c0
    i2c_adap = i2c_get_adapter(0);
    sensor_client = i2c_new_device(i2c_adap, &hi_info);//可以使用這個client進行i2c設置。因爲/
    *struct i2c_client {
    unsigned short flags;       /* div., see below      */
    unsigned short addr;        /* chip address - NOTE: 7bit    */
                    /* addresses are stored in the  */
                    /* _LOWER_ 7 bits       */
    char name[I2C_NAME_SIZE];
    struct i2c_adapter *adapter;    /* the adapter we sit on    */
    struct i2c_driver *driver;  /* and our access routines  */
    struct device dev;      /* the device structure     */
    int irq;            /* irq issued by device     */
    struct list_head detected;
};*/

    i2c_put_adapter(i2c_adap);
    return 0;
}

由此可以知道執行i2c_register_board_info並添加了i2c_boar_info後,在以後執行i2c_register_adapter的時候是會主動掃描__i2c_board_list中的靜態devinfo信息。如果沒有執行i2c_register_board_info,那麼可以通過i2c_new_device以模塊的形式被動創建client。在i2c_new_device的時候執行device_add->bus.match?probe:return.
在i2c_register_adapter中有

    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);

    /* Notify drivers */
    mutex_lock(&core_lock);
    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
    mutex_unlock(&core_lock);

即當在i2c總線上註冊適配器的時候,會掃描i2c總線上的drv,從i2c_bus_type.p.klist_drivers中查找驅動,遍歷到一個有效的驅動後執行__process_new_adapter(drv,adap); —>i2c_do_add_adapter—->i2c_detect(adap, driver)和driver->attach_adapter。顧名思義,其中的i2c_detect就是檢測i2c總線上可以使用的驅動是否與當前的適配器匹配。如果定義了i2c_driver的detect和address_list纔會匹配{ if (!driver->detect || !address_list)
return 0;},匹配成功則把製作的client結構體添加到driver->clients的鏈表中。不過這種方法用的很少,一般在i2c_driver中不處理detect和address信息,因此這種Notify driver的方式很少用。

    下面總結一下:
1.首先執行的是i2c_init-》bus_register(&i2c_bus_type);
postcore_initcall(i2c_init);
系統中有了i2c總線,才能將i2c總線的設備和驅動聯繫在一起。

2.完成i2c總線驅動即i2c適配器驅動,主要是adpter的algorithm成員。填充好adpter以後,用i2c_add_numbered_adapter--》i2c_register_adapter-->主動掃描__i2c_board_list中的i2c_board_info的i2c設備,如果有會執行i2c_new_device,並且在sys目錄下會看到想應name的目錄。--->掃描i2c總線上的所有驅動,來嘗試匹配該適配器(現在基本不用)。
3.在設備驅動層要完成的是定義i2c_board_info和i2c_driver。
這樣看上去,把i2c框架分成三層,i2c核心層、i2c總線層、i2c設備驅動層。這樣的劃分方式應該是更合理。其中i2c核心層定義了i2c適配器註冊註銷、i2cdriver註冊註銷,register_i2c_boardinfo、與具體的硬件無關的發生接收函數,如:i2c_master_send和i2c_master_recv。

加載模塊調用內核態 I2C 讀寫程序示例:
此操作示例在內核態下通過 I2C 讀寫程序實現對 I2C 外圍設備的讀寫操作。
步驟 1. 調用 I2C 核心層的函數,獲得描述一個 I2C 控制器的結構體 i2c_adap:
i2c_adap = i2c_get_adapter(2);
假設我們已經知道新增的器件掛載在 I2C 控制器 2 上,直接設置 i2c_get_adapter 的參數爲 2。
步驟 2. 把 I2C 控制器和新增的 I2C 外圍設備關聯起來,得到描述 I2C 外圍設備的客戶端結構
體 hi_client:
hi_client = i2c_new_device(i2c_adap, &hi_info);
hi_info 結構體提供了 I2C 外圍設備的設備地址
步驟 3. 調用 I2C 核心層提供的標準讀寫函數對外圍器件進行讀寫:
ret = i2c_master_send(client, buf, count);
ret = i2c_master_recv(client, buf, count);
其中i2c_master_send都是與具體的平臺和硬件無關的接口,由i2c-core層定義,其中主要的是client,這個client對應於一個i2c設備,i2c_client裏的adpter成員完成了i2c設備和CPU之間的通訊。

int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
{
    int ret;
    struct i2c_adapter *adap = client->adapter;
    struct i2c_msg msg;

    msg.addr = client->addr;
#ifdef CONFIG_ARCH_HI3516A
    msg.flags = client->flags;
#else
    msg.flags = client->flags & I2C_M_TEN;
#endif
    msg.len = count;
    msg.buf = (char *)buf;

    ret = i2c_transfer(adap, &msg, 1);

    /*
     * If everything went ok (i.e. 1 msg transmitted), return #bytes
     * transmitted, else error code.
     */
    return (ret == 1) ? count : ret;
}
EXPORT_SYMBOL(i2c_master_send);

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
    unsigned long orig_jiffies;
    int ret, try;

    /* REVISIT the fault reporting model here is weak:
     *
     *  - When we get an error after receiving N bytes from a slave,
     *    there is no way to report "N".
     *
     *  - When we get a NAK after transmitting N bytes to a slave,
     *    there is no way to report "N" ... or to let the master
     *    continue executing the rest of this combined message, if
     *    that's the appropriate response.
     *
     *  - When for example "num" is two and we successfully complete
     *    the first message but get an error part way through the
     *    second, it's unclear whether that should be reported as
     *    one (discarding status on the second message) or errno
     *    (discarding status on the first one).
     */

    if (adap->algo->master_xfer) {
#ifdef DEBUG
        for (ret = 0; ret < num; ret++) {
            dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
                "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
                ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
                (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
        }
#endif

        if (in_atomic() || irqs_disabled()) {
            ret = i2c_trylock_adapter(adap);
            if (!ret)
                /* I2C activity is ongoing. */
                return -EAGAIN;
        } else {
            i2c_lock_adapter(adap);
        }
        /* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (ret = 0, try = 0; try <= adap->retries; try++) {
            ret = adap->algo->master_xfer(adap, msgs, num);
            if (ret != -EAGAIN)
                break;
            if (time_after(jiffies, orig_jiffies + adap->timeout))
                break;
        }
        i2c_unlock_adapter(adap);
        return ret;
    } else {
        dev_dbg(&adap->dev, "I2C level transfers not supported\n");
        return -EOPNOTSUPP;
    }
}
EXPORT_SYMBOL(i2c_transfer);

而adap->algo->master_xfer就是與硬件和適配器有關的了,是驅動工程師要做的。如:
static const struct i2c_algorithm hi_i2c_algo = {
    .master_xfer    = hi_i2c_xfer,
    .functionality  = hi_i2c_func,
};
    adap->algo = &hi_i2c_algo;
    adap->dev.parent = &pdev->dev;
    adap->nr = pdev->id;
    adap->retries = CONFIG_HI_I2C_RETRIES;
    errorcode = i2c_add_numbered_adapter(adap);
static int hi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
        int num)
{
    struct hi_i2c *pinfo;
    int errorcode;
    pinfo = (struct hi_i2c *)i2c_get_adapdata(adap);
    pinfo->msgs = msgs;
    pinfo->msg_num = num;
    pinfo->msg_index = 0;
    if (msgs->flags & I2C_M_RD)
        errorcode = hi_i2c_read(pinfo);
    else
        errorcode = hi_i2c_write(pinfo);
    return errorcode;
}

以i2c-dev.c提供的接口,通過應用程序讀寫i2c設備的方法:
用戶態 I2C 讀寫程序示例:
此操作示例在用戶態下通過 I2C 讀寫程序實現對 I2C 外圍設備的讀寫操作。
步驟 1. 打開 I2C 總線對應的設備文件,獲取文件描述符:
fd = open(“/dev/i2c-2”, O_RDWR);
步驟 2. 通過 ioctl 設置外圍設備地址、外圍設備寄存器位寬和數據位寬
ret = ioctl(fd, I2C_SLAVE_FORCE, device_addr);
ioctl(fd, I2C_16BIT_REG, 0);
ioctl(fd, I2C_16BIT_DATA, 0);//ioctl 的第三個參數爲 0 表示 8bit 位寬,爲 1 表示 16bit 位寬。
步驟 3. 使用 read/wite 進行數據讀寫:
read(fd, recvbuf, reg_width);
write(fd, buf, (reg_width + data_width));

unsigned int reg_width = 1;
unsigned int data_width = 1;
unsigned int reg_step = 1;
HI_RET i2c_read(int argc, char* argv[])
{
 int fd = -1;
 int ret;
 unsigned int i2c_num, device_addr, reg_addr, reg_addr_end;
 char data;
 char recvbuf[4];
 int cur_addr;
 memset(recvbuf, 0x0, 4);
 fd = open("/dev/i2c-2", O_RDWR);
 if (fd<0)
 {
 printf("Open i2c dev error!\n");
 return -1;
 }
 ret = ioctl(fd, I2C_SLAVE_FORCE, device_addr);
 if (reg_width == 2)
 ret = ioctl(fd, I2C_16BIT_REG, 1);
 else
 ret = ioctl(fd, I2C_16BIT_REG, 0);
 if (ret < 0) {
 printf("CMD_SET_REG_WIDTH error!\n");
 close(fd);
 return -1;
 }
 if (data_width == 2)
 ret = ioctl(fd, I2C_16BIT_DATA, 1);
 else
 ret = ioctl(fd, I2C_16BIT_DATA, 0);
 if (ret < 0) {
 printf("CMD_SET_DATA_WIDTH error!\n");
 close(fd);
 return -1;
 }
 for (cur_addr = reg_addr; cur_addr < reg_addr_end + reg_width;
cur_addr += reg_step)
 {
 if (reg_width == 2) {
 recvbuf[0] = cur_addr & 0xff;
 recvbuf[1] = (cur_addr >> 8) & 0xff;
 } else
 recvbuf[0] = cur_addr & 0xff;
 ret = read(fd, recvbuf, reg_width);
 if (ret < 0) {
 printf("CMD_I2C_READ error!\n");
 close(fd);
 return -1;
 }
 if (data_width == 2) {
 data = recvbuf[0] | (recvbuf[1] << 8);
 } else
 data = recvbuf[0];
 printf("0x%x 0x%x\n", cur_addr, data);
 }
 close(fd);
 return 0;
}

i2c_write(int argc , char* argv[])
{
 int fd = -1;
 int ret =0, index = 0;
 unsigned int i2c_num, device_addr, reg_addr, reg_value;
 char buf[4];
 fd = open("/dev/i2c-2", O_RDWR);
 if(fd < 0)
 {
 printf("Open i2c dev error!\n");
 return -1;
 }
 ret = ioctl(fd, I2C_SLAVE_FORCE, device_addr);
 if (reg_width == 2)
 ret = ioctl(fd, I2C_16BIT_REG, 1);
 else
 ret = ioctl(fd, I2C_16BIT_REG, 0);
 if (data_width == 2)
 ret = ioctl(fd, I2C_16BIT_DATA, 1);
 else
 ret = ioctl(fd, I2C_16BIT_DATA, 0);
 if (reg_width == 2) {
 buf[index] = reg_addr & 0xff;
 index++;
 buf[index] = (reg_addr >> 8) & 0xff;
 index++;
 } else {
 buf[index] = reg_addr & 0xff;
 index++;
 }
 if (data_width == 2) {
 buf[index] = reg_value & 0xff;
 index++;
 buf[index] = (reg_value >> 8) & 0xff;
 index++;
 } else {
 buf[index] = reg_value & 0xff;
 index++;
 }
 write(fd, buf, (reg_width + data_width));
 if(ret < 0)
 {
 printf("I2C_WRITE error!\n");
 return -1;
 }
 close(fd);
 return 0;
}

下面簡單分析一下i2c-dev.c

static const struct file_operations i2cdev_fops = {
    .owner      = THIS_MODULE,
    .llseek     = no_llseek,
    .read       = i2cdev_read,
    .write      = i2cdev_write,
    .unlocked_ioctl = i2cdev_ioctl,
    .open       = i2cdev_open,
    .release    = i2cdev_release,
};
static int i2cdev_open(struct inode *inode, struct file *file)
{
    unsigned int minor = iminor(inode);
    struct i2c_client *client;
    struct i2c_adapter *adap;
    struct i2c_dev *i2c_dev;

    i2c_dev = i2c_dev_get_by_minor(minor);
    if (!i2c_dev)
        return -ENODEV;

    adap = i2c_get_adapter(i2c_dev->adap->nr);
    if (!adap)
        return -ENODEV;
        .......
}
static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
        loff_t *offset)
{
    char *tmp;
    int ret;

    struct i2c_client *client = file->private_data;

    if (count > 8192)
        count = 8192;

    tmp = kmalloc(count, GFP_KERNEL);
    if (tmp == NULL)
        return -ENOMEM;

#ifdef CONFIG_ARCH_HI3516A
    copy_from_user(tmp, buf, count);
#endif

    pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
        iminor(file->f_path.dentry->d_inode), count);

    ret = i2c_master_recv(client, tmp, count);
    if (ret >= 0)
        ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
    kfree(tmp);
    return ret;
}

static ssize_t i2cdev_write(struct file *file, const char __user *buf,
        size_t count, loff_t *offset)
{
    int ret;
    char *tmp;
    struct i2c_client *client = file->private_data;

    if (count > 8192)
        count = 8192;

    tmp = memdup_user(buf, count);
    if (IS_ERR(tmp))
        return PTR_ERR(tmp);

    pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
        iminor(file->f_path.dentry->d_inode), count);

    ret = i2c_master_send(client, tmp, count);
    kfree(tmp);
    return ret;
}
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    struct i2c_client *client = file->private_data;
    unsigned long funcs;

    dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
        cmd, arg);

    switch (cmd) {
    case I2C_SLAVE:
    case I2C_SLAVE_FORCE:
        /* NOTE:  devices set up to work with "new style" drivers
         * can't use I2C_SLAVE, even when the device node is not
         * bound to a driver.  Only I2C_SLAVE_FORCE will work.
         *
         * Setting the PEC flag here won't affect kernel drivers,
         * which will be using the i2c_client node registered with
         * the driver model core.  Likewise, when that client has
         * the PEC flag already set, the i2c-dev driver won't see
         * (or use) this setting.
         */
        if ((arg > 0x3ff) ||
            (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
            return -EINVAL;
        if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
            return -EBUSY;
        /* REVISIT: address could become busy later */
        client->addr = arg;
        return 0;
    case I2C_TENBIT:
        if (arg)
            client->flags |= I2C_M_TEN;
        else
            client->flags &= ~I2C_M_TEN;
        return 0;
    case I2C_PEC:
        if (arg)
            client->flags |= I2C_CLIENT_PEC;
        else
            client->flags &= ~I2C_CLIENT_PEC;
        return 0;
    case I2C_16BIT_REG:
        if (arg)
            client->flags |= I2C_M_16BIT_REG;
        else
            client->flags &= ~I2C_M_16BIT_REG;
        return 0;
    case I2C_16BIT_DATA:
        if (arg)
            client->flags |= I2C_M_16BIT_DATA;
        else
            client->flags &= ~I2C_M_16BIT_DATA;
        return 0;
    case I2C_FUNCS:
        funcs = i2c_get_functionality(client->adapter);
        return put_user(funcs, (unsigned long __user *)arg);

    case I2C_RDWR:
        return i2cdev_ioctl_rdrw(client, arg);

    case I2C_SMBUS:
        return i2cdev_ioctl_smbus(client, arg);

    case I2C_RETRIES:
        client->adapter->retries = arg;
        break;
    case I2C_TIMEOUT:
        /* For historical reasons, user-space sets the timeout
         * value in units of 10 ms.
         */
        client->adapter->timeout = msecs_to_jiffies(arg * 10);
        break;
    default:
        /* NOTE:  returning a fault code here could cause trouble
         * in buggy userspace code.  Some old kernel bugs returned
         * zero in this case, and userspace code might accidentally
         * have depended on that bug.
         */
        return -ENOTTY;
    }
    return 0;
}   
static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
        unsigned long arg)
{
    struct i2c_rdwr_ioctl_data rdwr_arg;
    struct i2c_msg *rdwr_pa;
    u8 __user **data_ptrs;
    int i, res;

    if (copy_from_user(&rdwr_arg,
               (struct i2c_rdwr_ioctl_data __user *)arg,
               sizeof(rdwr_arg)))
        return -EFAULT;

    /* Put an arbitrary limit on the number of messages that can
     * be sent at once */
    if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
        return -EINVAL;

    rdwr_pa = memdup_user(rdwr_arg.msgs,
                  rdwr_arg.nmsgs * sizeof(struct i2c_msg));
    if (IS_ERR(rdwr_pa))
        return PTR_ERR(rdwr_pa);

    data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
    if (data_ptrs == NULL) {
        kfree(rdwr_pa);
        return -ENOMEM;
    }

    res = 0;
    for (i = 0; i < rdwr_arg.nmsgs; i++) {
        /* Limit the size of the message to a sane amount;
         * and don't let length change either. */
        if ((rdwr_pa[i].len > 8192) ||
            (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
            res = -EINVAL;
            break;
        }
        data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
        rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
        if (IS_ERR(rdwr_pa[i].buf)) {
            res = PTR_ERR(rdwr_pa[i].buf);
            break;
        }
    }
    if (res < 0) {
        int j;
        for (j = 0; j < i; ++j)
            kfree(rdwr_pa[j].buf);
        kfree(data_ptrs);
        kfree(rdwr_pa);
        return res;
    }

    res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
    while (i-- > 0) {
        if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
            if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
                     rdwr_pa[i].len))
                res = -EFAULT;
        }
        kfree(rdwr_pa[i].buf);
    }
    kfree(data_ptrs);
    kfree(rdwr_pa);
    return res;
}
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
    unsigned long orig_jiffies;
    int ret, try;

    /* REVISIT the fault reporting model here is weak:
     *
     *  - When we get an error after receiving N bytes from a slave,
     *    there is no way to report "N".
     *
     *  - When we get a NAK after transmitting N bytes to a slave,
     *    there is no way to report "N" ... or to let the master
     *    continue executing the rest of this combined message, if
     *    that's the appropriate response.
     *
     *  - When for example "num" is two and we successfully complete
     *    the first message but get an error part way through the
     *    second, it's unclear whether that should be reported as
     *    one (discarding status on the second message) or errno
     *    (discarding status on the first one).
     */

    if (adap->algo->master_xfer) {
#ifdef DEBUG
        for (ret = 0; ret < num; ret++) {
            dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
                "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
                ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
                (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
        }
#endif

        if (in_atomic() || irqs_disabled()) {
            ret = i2c_trylock_adapter(adap);
            if (!ret)
                /* I2C activity is ongoing. */
                return -EAGAIN;
        } else {
            i2c_lock_adapter(adap);
        }

        /* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (ret = 0, try = 0; try <= adap->retries; try++) {
            ret = adap->algo->master_xfer(adap, msgs, num);
            if (ret != -EAGAIN)
                break;
            if (time_after(jiffies, orig_jiffies + adap->timeout))
                break;
        }
        i2c_unlock_adapter(adap);

        return ret;
    } else {
        dev_dbg(&adap->dev, "I2C level transfers not supported\n");
        return -EOPNOTSUPP;
    }
}
EXPORT_SYMBOL(i2c_transfer);

i2c-dev.c創建了字符設備,主設備號都是89.次設備號跟adpter-nr的值一樣,實現過程很簡單,就不多說了,主要依賴於i2c適配器的algorithm的master_xfer成員函數。當用到具體的應用的時候,需要結合I2c適配器的algorithm的master_xfer成員函數和芯片手冊。
如以下幾個I2C硬件模塊,其使用方法是不一樣的。
下面以幾個平臺的I2C硬件模塊爲例,介紹一下集成到芯片內部的I2C控制器。
1.如Xarina的I2C模塊,其中包含了64字節的RAM。其RAM地址空間分佈如下:
這裏寫圖片描述
在進行i2c寫操作的時候,需要在RAM中準備好SLAVE地址和REG、數據,可以是多字節寫入。硬件模塊中提供了ICRAM寄存器,裏面存放的是從RAM中發出或者讀入的字節數。當i2C總線上產生起始位後,後續會將RAM中的數據寫到總線上。在master端,軟件上只需要控制總線的開始、再次開始、NACK、ACK時鐘(只需要時鐘,不需要判斷SDA的電平,可以通過讀取狀態寄存器來判斷是否有應答,這個狀態寄存器是I2C硬件單元在通訊過程中自動更新的。發生NACK的時候也是硬件自動去發生的)、停止位。相對來說操作簡單,而且用法靈活。

2.再如海思3516、3520D、3521、3535的I2c模塊,則比較容易理解。其定義了ICR、TXR、RXR、CTRL、COMM寄存器。COMM寄存器的定義了起始位、停止位、讀/寫標誌位,TXR專門用於發送數據的寄存器。每當寫TXR寄存器後,再設置COMMAN寄存器,則會把數據從TXR傳送到總線上(如果是起始位則直接寫COMM即可)。如寫0xa2設備的0x50寄存器爲0xAA,則可以執行類似如下操作:
1.COMM.startbit=1 and COMM.writebit=1
2.waitfor_writeend(有專門狀態寄存器反饋)
3.TXR=0xa2
4.COMM.writebit=1
5.同2
6.TXR=0x50
7.同4
8.同2
9.TXR=0xAA
10.同4
11.同2
3.再如海思3516A。這個芯片的I2C模塊,操作更簡單。有一個I2C_MST_SINGLE_CTRL的寄存器,這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述

如果是讀操作,就置bit30爲1,如果爲寫操作就置bit30爲0。I2C硬件模塊會根據這個位的狀態來判斷是讀還是寫,還有一個寄存器MSG_CMD。這裏寫圖片描述
這個寄存器的bit[0-15]爲寫入或者讀入的數據,bit[16-31]爲需要讀/寫的寄存器地址。當然還有SLAVE_ADDRESS寄存器,這裏就不列出了。
因此我們如果要寫寄存器a8爲0x37話,只需要設置I2C_MST_SIGLE_CMD爲0xa837,將CTRL寄存器有0x80000000或上其他位的信息。在寫寄存器的之前要等TXFIFO不滿,要讀數據的之前,要等RX FIFO不爲空,當RXFIFO不空的時候,說明I2C硬件模塊已經將數據準備好了,並且放到了CMD寄存器的低16位,這個過程是硬件自動完成的。因此軟件的配置就顯得相當簡單,如要讀寄存器0xa8。那麼可以這樣做:
1. 設設置slave的器件地址
2.等待TX_FIFO非滿
3.寫入CMD【31-16】,0xa8
4.等待RX_FIFO非空
5.從CMD【15-0】中把I2C的數據給取出來。
如果要寫寄存器0xa8爲0x37。就更簡單了。
1. 設設置slave的器件地址
2. 等待TX_FIFO非滿
3. 寫入CMD【31-0】 爲0xa837
對於這個模塊,如下面要讀取一個I2c的從設備,他的寄存器地址是16bits,寄存器數據是8bits,則下面的例子,可能是達不到你要的效果。 跟蹤了一下HI3516A i2c驅動代碼。當第一次寫地址的時候,由於在寫的時候沒有準備寫入的數據,只是告訴從設備要讀取的地址。在驅動中就寫0到寄存器了。而第二次執行了讀操作,而讀的時候沒有指定寄存器地址,只是告訴了設備地址,因此是讀不正確的。可以嘗試只使用一個mgs。
讀的過程也可以猜出來了吧。由此可知,在使用應用程序讀寫i2c設備的時候,同樣的應用程序,在一個平臺正確,則換個平臺就不一定正確了,具體要看I2c模塊介紹和Kernel裏面的I2C驅動。

{
if((argc>3)&&(!strncmp("-r",argv[1],2))){
                e2prom_data.nmsgs=2;
                (e2prom_data.msgs[0]).len=2; //e2prom 目標數據的地址
                (e2prom_data.msgs[0]).addr=strtoul((const char *)argv[2],0,0); // e2prom 設備地址
                (e2prom_data.msgs[0]).flags&=~I2C_M_RD;//write
                (e2prom_data.msgs[0]).flags|=I2C_M_16BIT_REG;
                (e2prom_data.msgs[0]).flags&=~ I2C_M_16BIT_DATA;
                (e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);
                unsigned short buf = strtoul((const char *)argv[3],0,0);
                                printf("buf :%x\n", buf);
                (e2prom_data.msgs[0]).buf[1]=((buf>>8)&0xff);   //(unsigned char)atol(argv[3]);//e2prom數據地址(e2prom_data.msgs[0]).buf[0]=(buf>>8);   //(unsigned char)atol(argv[3]);//e2prom數據地址

                (e2prom_data.msgs[0]).buf[0]=(buf&0xff);    //(unsigned char)atol(argv[3]);//e2prom數據地址

                (e2prom_data.msgs[1]).len=1;//讀出的數據
                (e2prom_data.msgs[1]).addr=(e2prom_data.msgs[0]).addr;// e2prom 設備地址 
                (e2prom_data.msgs[1]).flags|=I2C_M_RD;//read
                (e2prom_data.msgs[1]).flags|=I2C_M_16BIT_REG;
                (e2prom_data.msgs[1]).flags&=~ I2C_M_16BIT_DATA;
                (e2prom_data.msgs[1]).buf=(unsigned char*)malloc(1);//存放返回值的地址。
                (e2prom_data.msgs[1]).buf[0]=0;//初始化讀緩衝


                ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章