To: I2C Driver Analysis

Source: Internet
Author: User
Document directory
  • Summary:

In fact, in the newer code (such as the linux-2.6.30 I use now) in fact has a general I2C driver. Therefore, in some simple scenarios, we don't actually need to write the driver any more. We only need to use it, but it is not a very simple task to use it, because there is very little content about this, sometimes we have to analyze the code to understand how to use it.

I2C code is relatively small, because the Protocol itself is not very complex. We can start with his code directory.

In Linux, the I2C driver code C files are basically stored in the drivers/I2C directory.

This folder contains the main code of I2C implementation in Linux.

The content includes three subfolders and three. c files.

Subfolders: algos busses chips

Algos mainly includes a time series algorithm when some bus transmits data.

Busses contains the I2C bus low-layer driver methods on different platforms.

Chips contains some known-core driving methods.

. C file

I2c-core.c, this file is the core of the I2C driver code, used to communicate VFS with lower-layer implementations.

I2c-dev.c is a general-purpose driver, basically most I2C drivers can call this operation. It generates an I2C device with the master device number 89 under/dev. It mainly implements the operations specified in VFS.

The i2c-boardinfo.c contains a board-level information.

There are not many codes in total. As mentioned above, there are not many codes that we need to care about,

From the compiled code directory, we found some traces. My code tree was compiled for mini2440. I found that only the following files are actually involved in Compilation:

I2c-core.c i2c-dev.c i2c-boardinfo.c under the root directory

I2c-algo-bit.c under Drivers/I2C/algos directory:

: I2c-s3c2410.c under the drivers/I2C/busses directory

Five in total. Although there are few files, the nested structure involved is very complicated. I tried to sort it out, but I found that the clues were messy and I was not able to figure out a clear line.

Taking a look at <Linux device driver development details> from the author's experience, this book is very helpful for understanding, but I also found that the charts in it are not perfect, however, in my opinion, it is not easy to sort it out.

The following describes the five files mentioned above. The three files mentioned above are described in the reference section. The following two i2c-algo-bit.c mainly involves some algorithm-related content. The i2c-s3c2410.c is the platform-related I2C Adapter Driver, that is, the bus driver.

First, we need to understand some concepts:

One, i2c-adapter, that is, I2C-adapter, this thing corresponds to the S3C2440 chip surface, that is, the i2c-controller on the chip, is I2C controller. The I2C adapter is used to generate a bus sequence to read and write I2C data from the device.

2. i2c-client, that is, I2C slave device, slave device, this thing represents a device connected to the S3C2440 chip, such as an AT24C08 EEPROM chip, or the camera control bus in the ov9650 camera core (note: In this camera chip, the official chip manual mentioned sccb bus is actually a weakened I2C bus, we can use the I2C driver to read and write it, which will be demonstrated later ).

First of all, we first from the i2c-dev.c this file began to analyze, one by one step to see from top to bottom is how to call.

This is a modular driver code, so let's start with the initialization code:

static int __init i2c_dev_init(void){ int res;  printk(KERN_INFO "i2c /dev entries driver\n");  res = register_chrdev(I2C_MAJOR, "i2c", &amp;i2cdev_fops); if (res)  goto out;  i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); if (IS_ERR(i2c_dev_class)) {  res = PTR_ERR(i2c_dev_class);  goto out_unreg_chrdev; }  res = i2c_add_driver(&amp;i2cdev_driver); if (res)  goto out_unreg_class;  return 0; out_unreg_class: class_destroy(i2c_dev_class);out_unreg_chrdev: unregister_chrdev(I2C_MAJOR, "i2c");out: printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__); return res;}

For the sake of simplicity, we should take away the less important things of this code first. Let's take a look at the important things and turn them:

static int __init i2c_dev_init(void){ int res; res = register_chrdev(I2C_MAJOR, "i2c", &amp;i2cdev_fops); i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); res = i2c_add_driver(&amp;i2cdev_driver);}

That is to say, the initialization code of this module has done three things:

1. Register a character device driver. Mark1

2. Register a class with sysfs.

3. Add a driver structure to the upper part. This third action is not a standard kernel action, but a i2c-core.c. Let's talk about this later. Mark2

First, let's talk about this character device.

Character device. I think anyone who has written the LED driver can understand it. The important part is the structure of the Primary and Secondary device numbers and file_operations.

The master device number i2c_major is defined in include/Linux/i2c-dev.h

Original Definition:

#define I2C_MAJOR       89              /* Device major number          */

The device number is not defined here.

The initialization in the original file of the file_operations structure is as follows:

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

Next we will briefly describe the role of each function and introduce some struct.

Generally, the first step of a device is to open the device node of the device. Let's see what happens when the device is turned on:

Here, we also want to simplify the file and only extract the important parts. You can view the original text in your code, or open on. USR. CC and search for the function name.

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) adap = i2c_get_adapter(i2c_dev-&gt;adap-&gt;nr);  client = kzalloc(sizeof(*client), GFP_KERNEL);  i2c_put_adapter(adap);  client-&gt;driver = &amp;i2cdev_driver;  client-&gt;adapter = adap; file-&gt;private_data = client;}

The first action here is i2c_dev_get_by_minor. This function is used to obtain an i2c_dev structure through the sub-device number.

The i2c_dev structure is a struct defined in the header of this file:

struct i2c_dev { struct list_head list; struct i2c_adapter *adap; struct device *dev;};

It has three members, list_head list, which indicates that the structure will eventually form a linked list. I2c_adapter * ADAP points to an i2c_adapter structure, and the i2c_adapter structure represents the I2C adapter on the hardware. That is to say, we can access the adapter through this structure. The last one is that device * Dev points to a device structure, but from the current knowledge, I still don't know what the device is. Therefore, we will mark mark3 here for future reference.

The simplified version of the i2c_dev_get_by_minor function is as follows:

static struct i2c_dev *i2c_dev_get_by_minor(unsigned index){ struct i2c_dev *i2c_dev;  list_for_each_entry(i2c_dev, &amp;i2c_dev_list, list)  if (i2c_dev-&gt;adap-&gt;nr == index)  return i2c_dev;}

That is to say, here we query a linked list (see the text in the same color above). The data items in this linked list are composed of i2c_dev structures. We accessed ADAP through i2c_dev, that is, the adapter, and found a member Nr stored in this adapter structure, which is actually the sub-device number. If the device number of an i2c_dev item is the same as that of the input device number, it is found. The i2c_dev structure is returned.

So far, we have been talking about the first action of the open function in the file_operations structure. The corresponding i2c_dev structure is also found through the device number, in this structure, you can access the adapter and a useless device structure. When the device number is open, it is obtained from the device node. The adapter structure does not know when and where to initialize.

Next, let's talk about the second action in the open function, i2c_get_adapter. This function action is puzzled. We already have i2c_dev, And he originally points to an adapter, why do I still call a function? I remember reading other people's articles and saying that I had something to pay attention to, but I don't remember. Mark4.

In short, an i2c_adapter structure is found here, that is, i2c_adapter can be used.

The third action of the open function generates an i2c_client structure, and the third action is to open up a memory area for it.

In the fourth action of the open function, the i2c_put_adapter function only calls module_put (), which means to reduce the reference count of the adapter. Why? Mark5

The fifth and sixth actions of the open function:

Client-> driver = & i2cdev_driver;

Client-> adapter = ADAP;

Here, i2cdev_driver is a global i2c_driver struct defined in the file header. The ADAP is the adapter we find through the sub-device node.

The last action of open is the same as when we write the character device driver:

File-> private_data = client;

Summary:

The above is about the action in open. An i2c_dev struct pointer is declared in it, but it will not be used later. But we know that the system maintains an i2c_dev linked list. I2c_dev can be used to locate the adapter and device ). In addition, the central structure of the driver is i2c_client, and the system also has a global variable i2c_dirver i2cdev_driver.

Dark table in the book: This i2cdev_driver may be compatible with the i2c_client.

At this point, the structure we connect to is:

I2c_dev

I2c_client

I2c_driver

I2c_adapter

Here, i2c_client is the first time to enter the stage of history.

Since then, we can obtain the client from FP in any location and access adapter and i2c_driver, but we do not know the source.

Next we will not talk about other functions in file_operations, because it makes no sense to talk about them. We will keep it first. So

We have not mentioned the following:

All functions except open in file_operations.

Okay, let's write it down. Then let's watch something else.

In i2c_dev, apart from a basic character device, there is something else.

Do you remember what we said in the module initialization function? There are three steps in it. We are talking about preparations for registering the character device.

Next, let's talk about the other two actions.

I. i2c_dev_class = class_create (this_module, "i2c-dev ");

Note that i2c_dev_class is also a global variable!

Static struct class * i2c_dev_class;

This sentence is in line 516 of my file. In fact, the implementation code of all the other two actions also starts from here.

After carefully reading the code, I found that the first use of this i2c_dev_class is the second action in the template initialization code. That is, the class_create function is called to fill in the pointer.

Then, i2c_dev_class also appears in two functions. Next to the sentence referenced above, there are two functions and a struct filling. Then there is the module initialization function. I simplified the middle section and post it:

static int i2cdev_attach_adapter(struct i2c_adapter *adap){ struct i2c_dev *i2c_dev; i2c_dev = get_free_i2c_dev(adap); i2c_dev-&gt;dev = device_create(i2c_dev_class, &amp;adap-&gt;dev,         MKDEV(I2C_MAJOR, adap-&gt;nr), NULL,         "i2c-%d", adap-&gt;nr); res = device_create_file(i2c_dev-&gt;dev, &amp;dev_attr_name);} static int i2cdev_detach_adapter(struct i2c_adapter *adap){ struct i2c_dev *i2c_dev; i2c_dev = i2c_dev_get_by_minor(adap-&gt;nr); device_remove_file(i2c_dev-&gt;dev, &amp;dev_attr_name); return_i2c_dev(i2c_dev);} static struct i2c_driver i2cdev_driver = { .driver = {  .name = "dev_driver", }, .attach_adapter = i2cdev_attach_adapter, .detach_adapter = i2cdev_detach_adapter,};

As you can see, the idea is clear from top to bottom. The two functions are written for the following struct, and the structure is written for the third step action in the module initialization function.

Let's first look at the first function: i2cdev_attach_adapter

The first action is get_free_i2c_dev. Remember the first step we mentioned in the open command above, which is to find a corresponding i2c_dev structure through the device number, that is, traverse an i2c_dev table and find it from it, however, we still don't know when the table was generated, but we still don't know it, but we can see some clues. In the get_free_i2c_dev function, its function is to initialize an i2c_dev structure, fill in the ADAP member with the input adapter and add the i2c_dev to the i2c_dev_list table (click the link above for details ).

Now we know the filling process of i2c_dev_list members. However, only one ADAP member is initialized in i2c_dev, and another device member is not initialized. This is the second action in the i2cdev_attach_adapter function: i2c_dev-> Dev = device_create (). Here, a function is called and its return value is used to initialize i2c_dev-> Dev, that is, the device member. Step 3: device_create_file create a node under sysfs. This function is called when the driver is registered or the adapter is registered.

In short, here i2cdev_driver is initialized, and then the thing is to call i2c_add_driver during module initialization, The i2c_add_driver is actually switched to i2c_add_driver in the i2c-core.c to complete some functions,

static inline int i2c_add_driver(struct i2c_driver *driver){       return i2c_register_driver(THIS_MODULE, driver);}

This function does not need to be carefully studied here. I just want to say that the last piece of code in it is To round all the drivers and call their attach_adapter function, this is the reason why the registration will be called.

Well, the article has been too long. This article is over and will be further decomposed later.

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.