Linux I²c Device driver Authoring (ii)

Source: Internet
Author: User

The three main members of Linux I²C subsystem I2c_adapter, I2c_driver and I2c_client are briefly described in (a). The relationship of the three is also described in the previous section. There should be a preliminary understanding of the Linux I²c subsystem. The following further analysis of their relationship to the code layer, I think the better the understanding of their relationship, the more conducive to the development and commissioning of the drive of the I²C device.

It may be more helpful to have a problem with your analysis, and after understanding it, you may have some questions about the following:

    • How is the I2c_adapter driver added?
    • What is the relationship between I2c_client and I2c_board_info?
I²c External API

Before you answer the question, you might want to take a look at what the Linux kernel's i²c subsystem does to the driver module's API. (from https://www.kernel.org/doc/htmldocs/device-drivers/i2c.html)

External data structure The struct i2c_driver-represents an i²c device-driven struct i2c_client-represents an i²c from the device struct i2c_board_info-created from the device i2c_board_info-creating a template I 2 c device macro, containing the name and address of the struct i2c_algorithm-represents the I²c transmission method struct I2C_BUS_RECOVERY_INFO-I2C bus recovery information? The newly added structure of the kernel is not very clear. External function Operation module_i2c_driver-Register I²C device driven macro definition i2c_register_board_info-static declaration (registration) I²c device, can be multiple i2c_verify_client-if the device is i2c_ The dev member of the client returns its parent pointer, otherwise NULL is returned. Used to verify whether the device is an I²C device I2C_LOCK_ADAPTER-I2C bus lock operation, will find the most root of the i2c_adapter. It means that your module must conform to the GPL to use this interface. Behind with the GPL stands. i2c_unlock_adapter-the previous anti-operation, gpli2c_new_device-by I2c_board_info information to declare an I²C device (client), gpli2c_unregister_device- The previous anti-operation, GPL. I2c_new_dummy-declares an i²c device named dummy (specified address), gpli2c_verify_adapter-verifies that the bus number is dynamically assigned to the i2c_adapteri2c_add_adapter-declaration i²c adapter. I2c_add_numbered_adapter-is also a declaration of the I²C adapter, but the bus number is specified, gpli2c_del_adapter-offload i²c adapter i2c_del_driver-Uninstall the I²C device driver I2c_use_ Client-i2c_client Reference Number +1i2c_release_client-i2c_client reference number -1__i2c_transfer-No auto-lock (Adapter lock) I²c Transport Interface I2c_transfer -Auto-lock I²c Transmission Interface i2c_master_send-Single message send i2c_master_recv-single message receive i2c_sMbus_read_byte-smbus "Receive byte" Protocoli2c_smbus_write_byte-smbus "Send Byte" protocoli2c_smbus_read_byte_data- SMBus "Read byte" Protocoli2c_smbus_write_byte_data-smbus "Write byte" Protocoli2c_smbus_read_word_data-smbus "Read W" Ord "Protocoli2c_smbus_write_word_data-smbus" Write word "Protocoli2c_smbus_read_block_data-smbus" block read "Protoc Oli2c_smbus_write_block_data-smbus "Block write" Protocoli2c_smbus_xfer-execute SMBus protocol operations

(a) a few basic structures and macro definitions also have a general explanation, I believe that the theoretical basis of integration is not difficult to understand. Categorize some of these i²c APIs:

No. Adapter Driver Device (client) Transfer
1 I2c_add_adapter Module_i2c_driver I2c_register_board_info __i2c_transfer
2 I2c_add_numbered_adapter I2c_del_driver I2c_new_device I2c_transfer
3 I2c_del_adapter I2c_new_dummy I2c_master_send
4 I2c_lock_adapter I2c_verify_client I2c_master_recv
5 I2c_unlock_adapter I2c_unregister_device I2c_smbus_read_byte
6 I2c_verify_adapter I2c_use_client I2c_smbus_write_byte
7 I2c_release_client I2c_smbus_read_byte_data
8 I2c_smbus_write_byte_data
9 I2c_smbus_read_word_data
10 I2c_smbus_write_word_data
11 I2c_smbus_read_block_data
12 I2c_smbus_write_block_data
13 I2c_smbus_xfer

After a form of collation, it is not difficult to find in the Linux i²c subsystem, the most important is the number of i2c_client, and the most diverse is the transmission of data.

For better understanding and cohesion, I think it might be helpful to have an analysis backwards, and here we will not discuss the details of the i²c transfer process in the first place. The order below is from the client to the driver, and then to the adapter.

Registration of I²C Client

I2c_client is an i²c device with three registered interfaces:

i2c_register_board_infoi2c_new_device i2c_new_dummy

And I2c_new_dummy in the inside is actually the name of the client is designated as dummy after the execution is still i2c_new_device, so only the first two to analyze it. First look at the prototypes of these two functions:

i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)

BusNum Specify which bus the device belongs to by bus number
Array collection I2c_board_info format for info i²c device
Len Array number array_size (info)

i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

ADAP the I²C adapter pointer to which this device is attached
Info This device description, i2c_board_info format, Bus_num member is ignored

I2c_register_board_info Concrete Implementation
 int __initi2c_register_board_info (int busnum, struct i2c_board_info const *info, unsigned len) {int status; Down_write (&__i2c_board_lock); I²c device Information read/write lock, Lock write operation, other read/* Dynamic bus numbers'll be assigned after the last static one */if (BusNum >= __i2c_f Irst_dynamic_bus_num)///With the dynamically assigned bus number, the dynamically assigned bus number should be +1 based on the existing maximum bus number, which ensures that the dynamically assigned bus number does not conflict with the board-level bus number __i2c_first_dynamic_ Bus_num = BusNum + 1; for (status = 0; len; len--, info++) {//process each member struct I2c_devinfo *devinfo in the info array; DevInfo = Kzalloc (sizeof (*devinfo), Gfp_kernel); if (!devinfo) {pr_debug ("I2c-core:can ' t Register boardinfo!\n"); status =-enomem; Break } devinfo->busnum = BusNum; Assembly Bus number devinfo->board_info = *info; Assembly Equipment Information List_add_tail (&devinfo->list, &__i2c_board_list); Added to the __i2c_board_list list (tail)} up_write (&__i2c_board_lock); Release read lock, other readable writable return status;} 

Do you believe that you will have a question after reading it? How to put the relevant information in the linked list even if it's done? Don't worry, take a look at the explanations given in the kernel:

 * Systems using the Linux I2C driver stack can declare tables of board info * while they initialize.  This should be done in board-specific init code * near arch_initcall() time, or equivalent, before any I2C adapter driver is * registered.  For example, mainboard init code could define several devices, * as could the init code for each daughtercard in a board stack. *  * The I2C devices will be created later, after the adapter for the relevant * bus has been registered.  After that moment, standard driver model tools * are used to bind "new style" I2C drivers to the devices.  The bus number * for any device declared using this routine is not available for dynamic * allocation.

The core content is that the integration of the I²C device registration process should be in the board level Code initialization, that is, the time before and after Arch_initcall, or at this time (BOARD-XXX-YYY.C), remember!!! Be sure to complete before the I²C adapter driver registration!!! Why is static registration, because the true i²c device is generated after the adapter is successfully registered. If you want to add an i²c device after the I²C adapter is registered, it will be done in a new way! (ie I2c_new_device)

The younger brother will always be in front of the boss! Eldest brother has not come out before, the younger brothers hurriedly before the array good, eldest brother to wait for you, your array also useless. And for the late younger brother, oneself try to chase up, in situ oneself array is wasted effort.

The process of how the information in the __i2c_board_list list becomes the actual i²c device information is placed after the analysis of the adapter registration process. Remember, the point is i2c_register_board_info way must be in the I²C adapter before registration, so there is no problem.

I2c_new_device
struct i2c_client *i2c_new_device (struct i2c_adapter *adap, struct I2c_board_info const *info) {struct i2c_client *c    lient;    int status;  Client = Kzalloc (sizeof *client, gfp_kernel);    Request Memory if (!client) return NULL for the client that is about to be registered;  Client->adapter = ADAP;  Binding the specified adapter adapter Client->dev.platform_data = info->platform_data;    Save device data if (info->archdata)//code see DMA related operation data Client->dev.archdata = *info->archdata;  Client->flags = info->flags;  Type, (i) said, or 10-bit address, or use SMBus to check the wrong client->addr = info->addr;  Device from address CLIENT->IRQ = info->irq;  Device Terminal strlcpy (Client->name, Info->type, sizeof (client->name)); From the device name//look!    (a) said I2c_board_info in the information is related to the i2c_client has the corresponding relationship, the efficacy of it!  /* Check for address validity */status = i2c_check_client_addr_validity (client); Detects if the address is valid, whether the 10-bit address is greater than the 0x3ff,7-bit address is greater than 0x7f or 0 if (status) {//Not 0 (actually-22, invalid parameter Invalid argument dev_err (&adap-&gt ;d ev, "Invalid%D-bit i²c 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);    Detects the address status on the specified adapter if (status) Goto Out_err;  Client->dev.parent = &client->adapter->dev;    Establish a parent-child relationship from the device to the adapter Client->dev.bus = &i2c_bus_type;    Client->dev.type = &i2c_client_type;    Client->dev.of_node = info->of_node;    Acpi_handle_set (&client->dev, Info->acpi_node.handle); /* For 10-bit clients, add a 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));  If it is a 10-bit address device, then the name format will be different from the 7bit status = Device_register (&client->dev); Register Now!    Registered!!!    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 i²c client%s at 0x%02x" "(%d) \ n", client    ->name, client->addr, status); Out_err_silent:kfree (client); return NULL;}

I2d_new_device there is not much to say, because of the i2c_register_board_info of the bedding, I believe it is also very good understanding. The I2c_new_device not only confirms the correspondence between I2c_client and I2c_board_info, but also shows a slight difference between the 10bit address device and the 7bit address device. Through the comparison between the two can be summed up a few differences, so as to better understand the registration method of I²C device:

    • The I2c_register_board_info parameter requires a bus number.
    • The I2c_new_device parameter needs to be directly the adapter's pointer

I think this is just perfect to explain the fundamental difference between the two, for board-level devices more care about the bus number of the adapter, because this is fixed, no objection. For pluggable devices, because their adapters may not be board-level integrated, they do not care about their bus numbers, but simply seek their adapter pointers for binding. The analysis behind adapter registration can prove this better.

    • I2c_register_board_info can register multiple i²c devices at the same time
    • I2c_new_device can only register one i²c device at a time

This is the fundamental difference between the decision, board-level code often contains a lot of i²c devices, so i2c_register_board_info need to have the ability to register multiple I²C devices at the same time can be said to be just needed. And I2c_new_device since is used for pluggable equipment, presumably the number of equipment is not much, and often may just a two, so one at a time is enough, the demand is not big.

I²c Driver

I²c device driver. The Linux kernel gives only two interfaces, one is registration and the other is uninstallation. In (a) also analyzed module_i2c_driver this macro definition, because there is its existence, i²c device driver development can not care about how your i²c driver need to register and how to uninstall, all the energy is put on the i2c_driver perfect on it.

Through the beginning of the form can be clearly realized that the I²C subsystem in the driver of the Open interface is the least, white is the need to drive the writer finished i2c_driver into the Module_i2c_driver macro can, and because of this, it is precisely explained that i2c_ The flexibility of driver is the highest. Usually the driver will be first in the user space to open, close, read and write interfaces, but for I2c_driver, these work is the I²C subsystem has been done, about the common reading and writing is finally achieved through the adapter I2c_algorithm achieve the goal. Well, once again, the degree of perfection of the I²C subsystem is extremely convenient for the development of I²C devices and drives. So what does the I²c drive achieve?

Look again at the i2c_driver structure, but now remove some of the less commonly used members:

struct i2c_driver {    int (*probe)(struct i2c_client *, const struct i2c_device_id *); //现行通用的与对应设备进行绑定的接口函数    int (*remove)(struct i2c_client *);  //现行通用与对应设备进行解绑的接口函数    void (*shutdown)(struct i2c_client *);  //关闭设备    int (*suspend)(struct i2c_client *, pm_message_t mesg); //挂起设备,与电源管理有关,为省电    int (*resume)(struct i2c_client *); //从挂起状态恢复    struct device_driver driver;  //I2C设备的驱动模型    const struct i2c_device_id *id_table;  //匹配设备列表    ...};

If possible, I would like to refine it again:

struct i2c_driver {    int (*probe)(struct i2c_client *, const struct i2c_device_id *); //现行通用的与对应设备进行绑定的接口函数    int (*remove)(struct i2c_client *);  //现行通用与对应设备进行解绑的接口函数    struct device_driver driver;  //I2C设备的驱动模型    const struct i2c_device_id *id_table;  //匹配设备列表    ...};

Well, to this extent, why the power management related also killed it? In fact, the actual i²c driver likes to do this in drivers (take mpu3050 as an example):

static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);static const struct i2c_device_id mpu3050_ids[] = {    { "mpu3050", 0 },    { }};MODULE_DEVICE_TABLE(i2c, mpu3050_ids);static const struct of_device_id mpu3050_of_match[] = {    { .compatible = "invn,mpu3050", },    { },};MODULE_DEVICE_TABLE(of, mpu3050_of_match);static struct i2c_driver mpu3050_i2c_driver = {    .driver    = {        .name    = "mpu3050",        .owner    = THIS_MODULE,        .pm    = &mpu3050_pm,        .of_match_table = mpu3050_of_match,    },    .probe        = mpu3050_probe,    .remove        = mpu3050_remove,    .id_table    = mpu3050_ids,};module_i2c_driver(mpu3050_i2c_driver);

As you can see, the actual driver likes to integrate power management into the driver members of I2c_driver.

Universal_dev_pm_ops is a very sharp name, seemingly "the ultimate drive power management Dafa of the Universe" looks like:

#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) const struct dev_pm_ops name = {     SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)     SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) }#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)     .suspend = suspend_fn,     .resume = resume_fn,     .freeze = suspend_fn,     .thaw = resume_fn,     .poweroff = suspend_fn,     .restore = resume_fn,#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)     .runtime_suspend = suspend_fn,     .runtime_resume = resume_fn,     .runtime_idle = idle_fn,

Combined with the MPU3050 drive, the full expansion can be achieved by:

static const struct dev_pm_ops mpu3050_pm = {    .suspend = mpu3050_suspend,    .resume = mpu3050_resume,    .freeze = mpu3050_suspend,    .thaw = mpu3050_resume,    .poweroff = mpu3050_suspend,    .restore = mpu3050_resume,    .runtime_suspend = mpu3050_suspend,    .runtime_resume = mpu3050_resume,    .runtime_idle = NULL,}

Interested in power management can go to consult the pm.h, which has a detailed description of power management, here does not do analysis. As you can see, in power management, there are a lot of members are actually the same, in the reality of this situation is also often seen in the driver, so there will be "the ultimate power Management DAFA" macro appeared.

Of_match_table is OpenFirmware related, in 3.0 (specific version I do not know) after the introduction of the ARM platform device Tree, the DTS configuration file can be replaced by a large number of board-level code, interested in self-access.

Said above, i2c_driver the most diversified, from the mpu3050 of the driver registration can also be found, its focus on the realization of probe and power management, which probe the most important (as if it is nonsense, which drive this is the most important-. -)。 Because the main is from the driving point of view of the I²C subsystem, so there is no detailed analysis of the mpu3050 code, just as an example to explain the general framework of the I²c Drive. In MPU3050 's probe, this sensor is mainly power-up, operation mode initialization, registering input subsystem interface, associated interrupt handler (escalation of three-axis parameters in interrupt processing thread) and so on.

A small summary of device drivers for i²c

I²c device drivers usually only need to mount in the I²c bus (that is, dependent on the I²C subsystem), I²C subsystem for the device driver is only a carrier, the cornerstone. The main core of many devices is based on other subsystems, such as gravity sensor, triaxial sensor, touch screen and so on, usually focus on input subsystem, while camera module, FM module, GPS module mostly depend on V4L2 subsystem. This also can be demonstrated by the I²C design concept, the production of i²c is to save the peripheral circuit complexity, so that the CPU uses a limited IO port to mount more external modules. Assuming that the CPU has enough expansion IO ports, I think there is no need for i²c to exist, after all, the direct operation of the IO Port drive device is simpler than the i²c.

The registration of I²C adapter

As shown in the table above, there are two ways to register for I²C adapter: I2c_add_adapter or I2c_add_numbered_adapter, the difference being that the latter has specified the bus number of this i²c adapter at the time of registration. The bus number of the former will be automatically assigned by the system.

Their respective declaration formats are:

int i2c_add_adapter(struct i2c_adapter *adapter)int i2c_add_numbered_adapter(struct i2c_adapter *adap)

Before i2c_add_numberd_adapter use must establish ADAP->NR, if give-1, explain or call the system to automatically generate bus number.

Usage Scenarios

The reason why two types of I²c adapter are registered is because their usage scenarios are different.

    • The use of I2c_add_adapter is often used to register those pluggable devices, such as USB PCI devices. The other modules on the motherboard are not directly connected to it, so to be blunt is that the existing module does not care what the bus number of the newly joined I²C adapter is because they do not need it. Instead, some modules on this pluggable device will require a successful adapter pointer to be registered. Looking back at the initial analysis of the i2c_client, you will find that the different scenarios of the device and its matching adapter has such a correspondence:

        1. i2c_register_board_info需要指定已有的busnum,而i2c_add_numbered_adapter注册前已经指定总线号;  2. i2c_new_device需要指定adapter指针,而i2c_add_adapter注册成功后恰好这个指针就有了。

      Imagine a scenario where a new device is plugged in and the corresponding driver registers its own I²C adapter via I2c_add_adapter, and then stores it as an adapter pointer somewhere, based on the agreement with the younger brothers, and says, "See?" When you register your own equipment, you can find me through this, and you can mix with me! "Then the driver continues, when the implementation to their own I²C device registration time, the younger brothers to the appointment location to find the oldest left mark, found effective information, swarmed:" Look! The boss is there!!! ”

    • The i2c_add_numbered_adapter is used to register an I²C adapter that comes with the CPU, or an I²C adapter that is integrated on the motherboard. The other i²c slave device (client) on the motherboard requires this bus number when registering.

Take a short code analysis to see how their differences are, and why statically registered i2c_client must be pre-registered with adapter (here it will streamline some of the code, leaving only important parts):

int i2c_add_adapter(struct i2c_adapter *adapter){    int    id, res = 0;    res = idr_get_new_above(&i2c_adapter_idr, adapter,                __i2c_first_dynamic_bus_num, &id);  //动态获取总线号    adapter->nr = id;    return i2c_register_adapter(adapter);  //注册adapter}int i2c_add_numbered_adapter(struct i2c_adapter *adap){    int    id;    int    status;    if (adap->nr == -1) /* -1 means dynamically assign bus id */        return i2c_add_adapter(adap);    status = i2c_register_adapter(adap);    return status;}

Visible, eventually they are all registered through the I2c_register_adapter adapter:

static int i2c_register_adapter (struct i2c_adapter *adap) {int res = 0; /* Can ' t register until after driver Model init *//Timing Check if (Unlikely (warn_on (!I2C_BUS_TYPE.P))) {res =-eaga        In;    Goto Out_list;  }/* Sanity checks */if (unlikely (adap->name[0] = = ')) {//Defensive code, check adapter name Pr_err ("I2c-core:attempt to        Register an adapter with "no name!\n");    Return-einval;                } if (unlikely (!adap->algo)) {//adapter has completed the implementation of the communication method Pr_err ("I2c-core:attempt to register adapter '%s ' with"        "No algo!\n", adap->name);    Return-einval;    } rt_mutex_init (&adap->bus_lock);    Mutex_init (&adap->userspace_clients_lock);    Init_list_head (&adap->userspace_clients);    /* Set default timeout to 1 second if not already set */if (adap->timeout = = 0) adap->timeout = HZ;    Dev_set_name (&adap->dev, "i2c-%d", ADAP-&GT;NR);    Adap->dev.bus = &i2c_bus_type; ADap->dev.type = &i2c_adapter_type;  res = Device_register (&adap->dev);    Register Device node if (res) goto out_list; /* Create pre-declared Device nodes *///creates pre-declared I²c device node if (Adap->nr < __i2c_first_dynamic_bus_num) i2c_        Scan_static_board_info (ADAP);        If the bus number of the adapter is less than the minimum of the dynamically assigned bus number, the description is board-level adapter.    The bus number assigned by the adapter joined by I2c_add_adapter must be larger than the __i2c_first_dynamic_bus_num. ...}

For I2c_add_numbered_adapter, the i2c_scan_static_board_info is triggered:

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) {  //又见__i2c_board_list,这不是通过i2c_register_board_info组建起来的那个链表吗!        if (devinfo->busnum == adapter->nr                && !i2c_new_device(adapter,                        &devinfo->board_info)) //找到总线号与刚注册的这个adapter相同的并通过i2c_new_device进行注册            dev_err(&adapter->dev,                "Can‘t create device at 0x%02x\n",                devinfo->board_info.addr);    }    up_read(&__i2c_board_lock);  //释放读写锁}

The corresponding action of I2c_board_info members and I2c_client is also carried out in I2c_new_device, which has been analyzed above. See here, the subtle relationship between adapter and client should understand the degree of deep, why say I2c_register_board_info and I2c_add_numbered_adapter correspond instead of i2c_add_ Adapter can also make sense.

So, the final answer to the two questions raised at the outset:

    • How is the I2c_adapter driver added?

Board-level adapter (CPU comes with, motherboard integration) to register via I2c_add_numbered_adapter, specify the bus number before registering, starting from 0. If the board-level I²C adapter registered 3, then the first dynamic bus number must be 3, that is, pluggable devices with the I²C adapter needs to be registered through I2c_add_adapter, the bus number is specified by the system.

    • What is the relationship between I2c_client and I2c_board_info?

The correspondence between I2c_client and I2c_board_info is fully embodied in I2c_new_device.

i2c_client->dev.platform_data = i2c_board_info->platform_data;i2c_client->dev.archdata = i2c_board_info->archdata;i2c_client->flags = i2c_board_info->flags;i2c_client->addr = i2c_board_info->addr;i2c_client->irq = i2c_board_info->irq;

Linux I²c Device driver Authoring (ii)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.