Detailed explanation of the I2C driver framework of the Linux kernel

Table of contents

1 I2C driver overall framework diagram  

2 I2C controller

2.1 I2C controller device--I2C controller is also regarded as a device in the kernel

2.2 i2c controller driver

2.3 What does the probe function in the platform_driver structure do

2.3.1 Question: Where does the i2cdev_notifier_call function come from?

2.3.2 Question: Why are there two probes?

2.3.3 Question: Do the functions of of_i2c_register_devices(adap); and bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter) overlap?

2.3.4 Questions: platform_bus_type and I2c_bus_type problems

2.3.5 Question: Why are the match and probe functions finally called in the i2c_imx_probe function?

3 i2c-core

4 i2c devices

4.1 i2c-client

4.2 i2c-driver

4.2.1 Question: In the i2c_register_driver function, it is enough to call the driver_register(&driver->driver); function to add a driver. Why is it also called i2c_for_each_dev(driver, __process_new_driver);

4.3 What does the probe function do?

4.3.1 Question: Why are there match and probe in at24_probe?

5 i2c-tools

5.1 Why i2c-tools is a set of useful tools

5.2 Why i2c-tools is also a set of sample codes

6 i2c_dev.c universal driver

7 GPIO analog I2C

8 Feynman learning method: So I recorded a learning video explaining the driver framework of the I2C subsystem.

references:


1 I2C driver overall framework diagram  

  The picture above is the overall framework of the I2C system, which is introduced as follows.

  • The top layer is the application layer. In the application layer, users can directly use open read and write to operate the device.
  • Next is the device driver layer, which is the peripheral, such as some sensors or EEPROM drivers connected to the SOC with the I2C bus. This is generally the responsibility of ordinary driver engineers.
  • The I2C-Core further down is the core layer. This is already in the Linux kernel source code. It mainly contains some driver and device registration functions and i2c_transfer functions.
  • Next is the I2C controller driver, which is usually written by programmers from the original chip factory.
  • Next comes the specific hardware.

The picture above is the I2C driver software framework, which is introduced as follows.

  • First, the rightmost one is the I2C device driver, which is divided into i2c-client and i2c-driver. The i2c device driver is mounted on i2c_bus_type, where i2c-client comes from the device tree file and is converted into i2c- through the of_i2c_register_devices(adap); function. client, and then added to the bus's device list, and then the i2c_driver structure is added to the bus's driver list through the registration function. When a driver or device is added, the bus's mach function will be called for matching, and then the probe function in the driver will be called. , add a structure in the probe function, and then this structure contains the read and write functions of the device.
  • The leftmost one is the I2C controller driver, in which the i2c node of the device tree is converted into platform_device, and then added to the device list of platform_bus_type, and then there is a platform_driver driver structure, which is registered in the driver list of platform_bus_type, and then When adding a device and driver, the platform_match function will be called. After matching, the i2x_imx_probe function in the platform_driver driver will be called.
  • The middle is the work done in the i2x_imx_probe function. This function first calls device_register to add the adapter to the device structure of i2c_bus_type. Note that it is i2c_bus_type, not platform_bus_type. The adapter contains an algorithm member. This algorithm contains the master_xfer function, i2c- The i2c_transfer function in the core is the master_xfer function in the algorithm called, and then of_i2c_register_device is also called in the i2x_imx_probe function to add i2c-client.

According to the Feynman learning method, speaking out knowledge points can deepen your understanding of the knowledge points, so I recorded a video on the I2C subsystem and sent it to Station B:

8 minutes to explain the overall framework of the Linux kernel I2C driver_哔哩哔哩_bilibili

The above is an overall introduction to the i2c driver. The following introduces the relevant content of the i2c controller, i2c-core and i2c device driver.

2 I2C controller

2.1 I2C controller device--I2C controller is also regarded as a device in the kernel

First look at the i2c controller device, you can see the i2c node in the ./Linux-4.9.88/arch/arm/boot/dts/imx6ull.dtsi device tree file,

            i2c1: i2c@021a0000 {                 #address-cells = <1>;                 #size-cells = <0>;                 compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";                 reg = <0x021a0000 0x4000>;                 interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;                 clocks = <&clks IMX6UL_CLK_I2C1>;                 status = "disabled"; #In actual use, this place should be changed to "okay".             };







of_platform_default_populate(NULL, NULL, parent); The function converts the I2C node into platform_device and adds the device. The specific function calling relationship is as follows:

of_platform_default_populate(NULL, NULL, parent);

    of_platform_populate(root, of_default_bus_match_table, lookup,parent);

        of_find_node_by_path("/")//Find the root node of the device tree

        of_platform_bus_create//This function will be called cyclically

            of_platform_device_create_pdata

                 of_device_alloc(np, bus_id, parent);

                 of_device_add(dev)

                     device_add(&ofdev->dev);

                         bus_add_device(dev);

                             klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);Add to linked list

                         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,调用bus_notifier

                         i2cdev_notifier_call

                               i2cdev_attach_adapter                                

                               if (dev->type != &i2c_adapter_type)//return device_create directly without calling

                                   return 0;

                                   device_create//Add i2c-%d node

                       bus_probe_device(dev);

                           device_initial_probe(dev);

                               __device_attach(dev, true);                               

                                   bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);

                                       __device_attach_driver

                                           driver_match_device(drv, dev);

                                               drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                           driver_probe_device(drv, dev);

                                                 really_probe(dev, drv);

                                                     dev->bus->probe(dev);或drv->probe(dev)

    

Finally, call the i2c_imx_probe function in the platform_driver structure. The i2c_imx_probe function will be analyzed later. The platform_device device will be seen here first.

static struct platform_driver i2c_imx_driver = {
	.probe = i2c_imx_probe,
	.remove = i2c_imx_remove,
	.driver = {
		.name = DRIVER_NAME,
		.pm = I2C_IMX_PM_OPS,
		.of_match_table = i2c_imx_dt_ids,
	},
	.id_table = imx_i2c_devtype,
};

2.2 i2c controller driver

The corresponding driver file can be found in the Linux source code through the compatible attribute value of the previous i2c1 node. There are two compatible attribute values ​​​​of the i2c1 node here: "fsl,imx6ul-i2c" and "fsl,imx21-i2c". Search these two strings in the Linux source code to find the corresponding driver file. The I2C adapter driver file of I.MX6U is drivers/i2c/busses/i2c-imx.c. The above i2c controller device is finally converted to platform_device, so the i2c controller driver also uses platform_driver and is mounted on platform_bus_type.

When looking at a driver, start with the entry function. We find the i2c_adap_imx_init function in the drivers/i2c/busses/i2c-imx.c file. First, call platform_driver_register(&i2c_imx_driver) to register the i2c_imx_driver structure. The specific function calling relationship is as follows, and then when match When the function finds that the driver and device match, it will call the probe function in the driver, which is the i2c_imx_probe function.

platform_driver_register(&i2c_imx_driver);

    __platform_driver_register(drv, THIS_MODULE)  

        drv->driver.owner = owner;

        drv->driver.bus = &platform_bus_type;

        drv->driver.probe = platform_drv_probe;

        drv->driver.remove = platform_drv_remove;

        drv->driver.shutdown = platform_drv_shutdown;

        driver_register(&drv->driver);    

            bus_add_driver(drv);

                klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);Put the driver into klist_driver

                driver_attach(drv);

                    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

                        __driver_attach

                            driver_match_device(drv, dev);

                                drv->bus->match ? drv->bus->match(dev, drv) : 1; 

                           driver_probe_device(drv, dev);

                               ret = really_probe(dev, drv);

                                   dev->bus->probe(dev);或drv->probe(dev) 

2.3 What does the probe function in the platform_driver structure do

When a new device or driver is added, the match function of the bus will be called, and then the match function will match the device and driver according to the compatible attribute value or name.

 * Platform device IDs are assumed to be encoded like this:
 * "<name><instance>", where <name> is a short description of the type of
 * device, like "pci" or "floppy", and <instance> is the enumerated
 * instance of the device, like '0' or '42'.  Driver IDs are simply
 * "<name>".  So, extract the <name> from the platform_device structure,
 * and compare it against the name of the driver. Return whether they match
 * or not.
 */
static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

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

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);
}

After matching, the probe function in the driver structure will be called. Next, let's take a look at what the i2c_imx_probe function in the struct platform_driver i2c_imx_driver structure does.

static struct platform_driver i2c_imx_driver = {
	.probe = i2c_imx_probe,
	.remove = i2c_imx_remove,
	.driver = {
		.name = DRIVER_NAME,
		.pm = I2C_IMX_PM_OPS,
		.of_match_table = i2c_imx_dt_ids,
	},
	.id_table = imx_i2c_devtype,
};

The specific function calling relationship is as follows:

i2c_imx_probe

    i2c_add_numbered_adapter

        __i2c_add_numbered_adapter

           i2c_register_adapter

               device_register(&adap->dev);

                   device_add(dev);

                       bus_add_device(dev);

                           klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);Add to linked list

                       blocking_notifier_call_chain(&dev->bus->p->bus_notifier,调用bus_notifier

                           i2cdev_notifier_call

                               i2cdev_attach_adapter

                                   device_create//Add i2c-%d node

                       bus_probe_device(dev);

                           device_initial_probe(dev);

                               __device_attach(dev, true);                               

                                   bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);

                                       __device_attach_driver

                                           driver_match_device(drv, dev);

                                               drv->bus->match ? drv->bus->match(dev, drv) : 1;//If the match is unsuccessful, return directly.

                                           driver_probe_device(drv, dev); The above match is unsuccessful, so it is not called directly here.

                                                 really_probe(dev, drv);

                                                     dev->bus->probe(dev);或drv->probe(dev),

               of_i2c_register_devices(adap);

                    of_i2c_register_device(adap, node);

                        i2c_new_device(adap, &info); used to increase client

                        client->dev.parent = &client->adapter->dev;

                        client->dev.bus = &i2c_bus_type;//Note that this is i2c-bus, not platform_bus

                        client->dev.type = &i2c_client_type;

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

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

                            status = device_register(&client->dev);Register a new i2c_client device

                                device_add(dev);

                                    bus_add_device(dev); 

                                        klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);

                                    bus_probe_device

                                        device_initial_probe(dev);

                                            __device_attach(dev, true);

                                                bus_for_each_drv

                                                      __device_attach_driver       

                                                          driver_match_device

                                                             drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                                          driver_probe_device(drv, dev);

                                                              really_probe(dev, drv);

                                                                  dev->bus->probe(dev);或drv->probe(dev)

                bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter)

                    __process_new_adapter(struct device_driver *d, void *data)                 

                        i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap)

                            i2c_detect(adap, driver); Detect whether there is a suitable device connected to the bus through i2c_detect

                                if (!driver->detect || !address_list) return 0; If detect or address_list is not defined, it will return directly

                                i2c_detect_address(temp_client, driver);

                                    err = driver->detect(temp_client, &info); Send a test data according to the corresponding client. If there is no problem, it proves that the client is the device required by the driver. Finally, the device is added to the linked list, and finally bus_probe_device is called to try to bind the driver.

                                    client = i2c_new_device(adapter, &info); used to increase client

                                         device_register(&client->dev);

                                             device_add(dev);   

                                                 bus_add_device(dev);

                                                     klist_add_tail

                                                 bus_probe_device(dev);

                                                     bus_probe_device(dev);

                                                         device_initial_probe(dev);

                                                             __device_attach(dev, true);

                                                                 bus_for_each_drv

                                                                     __device_attach_driver

                                                                         driver_match_device(drv, dev);

                                                                             drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                                                         driver_probe_device(drv, dev);

                                                                             really_probe(dev, drv);

                                                                                 dev->bus->probe(dev);或drv->probe(dev)

                    

        

I was looking at the kernel code and got the above function call flow, but at the same time I have the following questions or questions;

2.3.1 Question:  Where does the i2cdev_notifier_call function come from?

In the above process, why blocking_notifier_call_chain(&dev->bus->p->bus_notifier, calling bus_notifier will call i2cdev_notifier_call, the reason is here.

static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
  		 void *data)
{
  	struct device *dev = data;
  
  	switch (action) {
  	case BUS_NOTIFY_ADD_DEVICE:
  		return i2cdev_attach_adapter(dev, NULL);
  	case BUS_NOTIFY_DEL_DEVICE:
  		return i2cdev_detach_adapter(dev, NULL);
  	}
  
  	return 0;
}
  
static struct notifier_block i2cdev_notifier = {
  	.notifier_call = i2cdev_notifier_call,
};
  
static int __init i2c_dev_init(void)
{
	...
	res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
	...
}

2.3.2 Question: Why are there two probes?

There is a probe function in the platform_driver structure.

static struct platform_driver i2c_imx_driver = {
	.probe = i2c_imx_probe,
	.remove = i2c_imx_remove,
	.driver = {
		.name = DRIVER_NAME,
		.pm = I2C_IMX_PM_OPS,
		.of_match_table = i2c_imx_dt_ids,
	},
	.id_table = imx_i2c_devtype,
};

But when registering this driver, why is there a platform_drv_probe function in it?

 */
int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;
	drv->driver.bus = &platform_bus_type;
	drv->driver.probe = platform_drv_probe;
	drv->driver.remove = platform_drv_remove;
	drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

After looking at the code, I found that this is because the outer platform_drv_probe actually calls the probe in the platform_driver.

static int platform_drv_probe(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);
	struct platform_device *dev = to_platform_device(_dev);
	int ret;

	ret = of_clk_set_defaults(_dev->of_node, false);
	if (ret < 0)
		return ret;

	ret = dev_pm_domain_attach(_dev, true);
	if (ret != -EPROBE_DEFER) {
		if (drv->probe) {
			ret = drv->probe(dev);  //在这个地方调用了platform_driver的probe函数
			if (ret)
				dev_pm_domain_detach(_dev, true);
		} else {
			/* don't fail if just dev_pm_domain_attach failed */
			ret = 0;
		}
	}

	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
		dev_warn(_dev, "probe deferral not supported\n");
		ret = -ENXIO;
	}

	return ret;
}

2.3.3 Question: Do the functions of of_i2c_register_devices(adap); and bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter) overlap?

When looking at the function calling process above, I found that of_i2c_register_devices(adap); and bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter) functions both call i2c_new_device to add i2c-client. Isn’t that a duplicate of the function? Look carefully. After reading the code, I found that it should be like this, of_i2c_register_devices(adap); is to obtain the device information from the device tree node, and then register the i2c-client, and bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter) is actually calling i2c_detect, and then based on The detect function and address_list defined in the driver detect the i2c-client on the bus. This is equivalent to different methods of adding a client. For detailed explanation, please see this document of the kernel: Several methods of instantiating i2c devices in the Linux kernel-- --./Linux-4.9.88/Documentation/i2c/instantiating-devices file translation_Chen Hongwei's blog-CSDN blog 

2.3.4 Questions: platform_bus_type and I2c_bus_type problems

Note that in the function i2c_adap_imx_init

static int __init i2c_adap_imx_init(void)
{
	return platform_driver_register(&i2c_imx_driver);
}

Then further call __platform_driver_register, the bus at this time is platform_bus_type

int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;
	drv->driver.bus = &platform_bus_type;
	drv->driver.probe = platform_drv_probe;
	drv->driver.remove = platform_drv_remove;
	drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

 However, when registering the adapter (controller) in the probe in the driver, the i2c_add_numbered_adapter interface is called. The bus at this time is i2c_bus_type.

static int i2c_register_adapter(struct i2c_adapter *adap)
{
	...

	dev_set_name(&adap->dev, "i2c-%d", adap->nr);
	//BUS指向I2C
	adap->dev.bus = &i2c_bus_type;
	adap->dev.type = &i2c_adapter_type;
	res = device_register(&adap->dev);
	...

I looked at the code carefully and understood it. In fact, it is like this. The I2C node in the device tree node is indeed converted into platform_device and then mounted on the platform_bus bus. Then when the match function of platform_bus_type finds that the device matches the driver, call The probe function in the driver structure, then build the adapter in the probe function and add it, and then the adapter is added to i2c_bus_type.

2.3.5 Question: Why the i2c_imx_probe function finally calls the match and probe functions

This  i2c_imx_probe function is called when the match function of plarform_bus_type finds that the controller driver and the controller device match, and then adds an adapter to it, but how come there is drv->bus-> in the layers inside the i2c_imx_probe function ? match? drv->bus->match(dev, drv): 1; and dev->bus->probe(dev); or drv->probe(dev) function. Why is probe called again in probe? What about the internal What is the probe used for? 

i2c_imx_probe

    i2c_add_numbered_adapter

        __i2c_add_numbered_adapter

           i2c_register_adapter

               device_register(&adap->dev);

                   device_add(dev);

                       bus_add_device(dev);

                           klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);Add to linked list

                       blocking_notifier_call_chain(&dev->bus->p->bus_notifier,调用bus_notifier

                           i2cdev_notifier_call

                               i2cdev_attach_adapter

                                   device_create//Add i2c-%d node

                       bus_probe_device(dev);

                           device_initial_probe(dev);

                               __device_attach(dev, true);                               

                                   bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);

                                       __device_attach_driver

                                           driver_match_device(drv, dev);

                                               drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                           driver_probe_device(drv, dev);

                                                 really_probe(dev, drv);

                                                     dev->bus->probe(dev);或drv->probe(dev)

Why is there a probe in it? I can’t understand it. It’s hard to understand. I went to the kernel code and checked the calling process of the i2c_imx_probe function. I found that it should be like this, but I’m not sure if my understanding is correct . It is no problem to add any adapter in the previous ones. When registering the adapter, the bus is i2c_bus_tyupe.

static int i2c_register_adapter(struct i2c_adapter *adap)
{
    ...
 
    adap->dev.bus = &i2c_bus_type;
	adap->dev.type = &i2c_adapter_type;
	res = device_register(&adap->dev);

     ...
  
}

Then, when it comes to drv->bus->match, here, the bus is i2c_bus_type, then the call is 

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};

 Then that is

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;

	/* Then ACPI style match */
	if (acpi_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;
}

Then since the adapter device is added here, then if (!client) is not true at all, so the match here is 0, then

static int __device_attach_driver(struct device_driver *drv, void *_data)
{
	struct device_attach_data *data = _data;
	struct device *dev = data->dev;
	bool async_allowed;
	int ret;

	/*
	 * Check if device has already been claimed. This may
	 * happen with driver loading, device discovery/registration,
	 * and deferred probe processing happens all at once with
	 * multiple threads.
	 */
	if (dev->driver)
		return -EBUSY;

	ret = driver_match_device(drv, dev);
	if (ret == 0) {
		/* no match */
		return 0;
	} else if (ret == -EPROBE_DEFER) {
		dev_dbg(dev, "Device match requests probe deferral\n");
		driver_deferred_probe_add(dev);
	} else if (ret < 0) {
		dev_dbg(dev, "Bus failed to match device: %d", ret);
		return ret;
	} /* ret > 0 means positive match */

	async_allowed = driver_allows_async_probing(drv);

	if (async_allowed)
		data->have_async = true;

	if (data->check_async && async_allowed != data->want_async)
		return 0;

	return driver_probe_device(drv, dev);
}

Since the driver_match_device(drv, dev); function directly returns 0, then the __device_attach_driver function will return directly, and the driver_probe_device(drv, dev); function will not be called.

3 i2c-core

 The matching process of I2C devices and drivers is completed by the I2C core. drivers/i2c/i2c-core.c is the core
part of I2C. The I2C core provides some API functions that have nothing to do with specific hardware, such as mentioned before: 
  1 , i2c_adapter registration/cancellation function 
int i2c_add_adapter(struct i2c_adapter *adapter) 
int i2c_add_numbered_adapter(struct i2c_adapter *adap) 
void i2c_del_adapter(struct i2c_adapter * adap) 
  2. i2c_driver registration/cancellation function 
int i2c_register_driver(struct module *owner, struct i2c_driver *driver) 
int i2c_add_driver (struct i2c_driver *driver) 
void i2c_del_driver (struct i2c_driver *driver) 
The matching process between the device and the driver is also completed by the I2C bus. The data structure of the I2C bus is i2c_bus_type, which is defined
in the drivers/i2c/i2c-core.c file.

In addition, there is an i2c_transfer function in i2c-core, and then the i2c_transfer function is used directly in the device driver to send data, and this i2c_transfer function ultimately calls the master_xfer function in the algorithm in the adapter. It can also be seen from here that i2c-core plays a role A link between the previous and the next, connecting the device driver and the controller driver.

4 i2c devices

4.1 i2c-client

i2c-client comes from the device tree file and is generally placed in the child node of the i2c node, such as the ap3216 device below.

&i2c1 {         ap3216c@1e {             compatible = "lite-on,ap3216c";             reg = <0x1e>;         };/*The child nodes in i2c are used to represent i2c devices*/ };




&i2c1 {     clock-frequency = <100000>;     pinctrl-names = "default";     pinctrl-0 = <&pinctrl_i2c1>;     status = "okay"; };/*This is used to represent the i2c controller, not the i2c device */




The sub-nodes under the i2c bus node will not be converted into platform_device, they are processed by the I2C bus driver, and the conversion of the device node under the I2C into a client is actually done by the probe function in the i2c controller driver, which has been described above After analyzing the internal process of the probe function, the of_i2c_register_devices function in the middle part is used to add i2c-client.

i2c_imx_probe

    i2c_add_numbered_adapter

        __i2c_add_numbered_adapter

           i2c_register_adapter

               device_register(&adap->dev);

                   device_add(dev);

                       bus_add_device(dev);

                           klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);Add to linked list

                       blocking_notifier_call_chain(&dev->bus->p->bus_notifier,调用bus_notifier

                           i2cdev_notifier_call

                               i2cdev_attach_adapter

                                   device_create//Add i2c-%d node

                       bus_probe_device(dev);

                           device_initial_probe(dev);

                               __device_attach(dev, true);                               

                                   bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);

                                       __device_attach_driver

                                           driver_match_device(drv, dev);

                                               drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                           driver_probe_device(drv, dev);

                                                 really_probe(dev, drv);

                                                     dev->bus->probe(dev);或drv->probe(dev)

               of_i2c_register_devices(adap);

                    of_i2c_register_device(adap, node);

                        i2c_new_device(adap, &info); used to increase client

                        client->dev.parent = &client->adapter->dev;

                        client->dev.bus = &i2c_bus_type;//Note that this is i2c-bus, not platform_bus

                        client->dev.type = &i2c_client_type;

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

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

                            status = device_register(&client->dev);Register a new i2c_client device

                                device_add(dev);

                                    bus_add_device(dev); 

                                        klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);

                                    bus_probe_device

                                        device_initial_probe(dev);

                                            __device_attach(dev, true);

                                                bus_for_each_drv

                                                      __device_attach_driver       

                                                          driver_match_device

                                                             drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                                          driver_probe_device(drv, dev);

                                                              really_probe(dev, drv);

                                                                  dev->bus->probe(dev);或drv->probe(dev)

                bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter)

                    __process_new_adapter(struct device_driver *d, void *data)                 

                        i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap)

                            i2c_detect(adap, driver); Detect whether there is a suitable device connected to the bus through i2c_detect

                                if (!driver->detect || !address_list) return 0; If detect or address_list is not defined, it will return directly

                                i2c_detect_address(temp_client, driver);

                                    err = driver->detect(temp_client, &info); Send a test data according to the corresponding client. If there is no problem, it proves that the client is the device required by the driver. Finally, the device is added to the linked list, and finally bus_probe_device is called to try to bind the driver.

                                    client = i2c_new_device(adapter, &info); used to increase client

                                         device_register(&client->dev);

                                             device_add(dev);   

                                                 bus_add_device(dev);

                                                     klist_add_tail

                                                 bus_probe_device(dev);

                                                     bus_probe_device(dev);

                                                         device_initial_probe(dev);

                                                             __device_attach(dev, true);

                                                                 bus_for_each_drv

                                                                     __device_attach_driver

                                                                         driver_match_device(drv, dev);

                                                                             drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                                                         driver_probe_device(drv, dev);

                                                                             really_probe(dev, drv);

                                                                                 dev->bus->probe(dev);或drv->probe(dev)

                    

         

4.2 i2c-driver

i2c_driver uses this bus structure

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};

Let’s start with the entry function module_init(at24_init);, which calls i2c_add_driver(&at24_driver);, then calls i2c_register_driver(THIS_MODULE, driver), and then calls driver_register(&driver->driver); and then calls it further. Bus_add_driver(drv);, and then continue to call driver_attach(drv); and then continue bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); This function is to call the __driver_attach function for each device, then go in The __driver_attach function found that there are two important functions in it

  • driver_match_device(drv, dev);
  • driver_probe_device(drv, dev);

driver_match_device(drv, dev); which further calls drv->bus->match(dev, drv), which is the match function in i2c_bus_type.

driver_probe_device(drv, dev); further calls really_probe(dev, drv);, and then further calls dev->bus->probe(dev);. This is the probe function in i2c_bus_type.

i2c_add_driver(&at24_driver)

    i2c_register_driver(THIS_MODULE, driver)

        driver_register(&driver->driver)

             bus_add_driver(drv)

                  klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers) puts the driver into klist_driver

                  driver_attach(drv)

                      bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

                         __driver_attach(struct device *dev, void *data)

                             driver_match_device(drv, dev);

                                 drv->bus->match ? drv->bus->match(dev, drv) : 1; 

                              driver_probe_device(drv, dev);

                                  really_probe(dev, drv);

                                      dev->bus->probe(dev);或drv->probe(dev)   

    /* Walk the adapters that are already present */

    i2c_for_each_dev(driver, __process_new_driver);//

        __process_new_driver //The following code will not be called, and return directly from here.          

            i2c_do_add_adapter(struct i2c_driver *driver,struct i2c_adapter *adap)

                i2c_detect(adap, driver); 

                   if (!driver->detect || !address_list) return 0; If detect or address_list is not defined, it will be returned directly

                        i2c_detect_address(temp_client, driver);

                            err = driver->detect(temp_client, &info);

                                client = i2c_new_device(adapter, &info);

                                     device_register(&client->dev);

                                         device_add(dev);   

                                             bus_add_device(dev);

                                                 klist_add_tail

                                             bus_probe_device(dev);

                                                 bus_probe_device(dev);

                                                     device_initial_probe(dev);

                                                         __device_attach(dev, true);

                                                             bus_for_each_drv

                                                                 __device_attach_driver

                                                                     driver_match_device(drv, dev);

                                                                         drv->bus->match ? drv->bus->match(dev, drv) : 1;

                                                                      driver_probe_device(drv, dev);

                                                                          really_probe(dev, drv);

                                                                             dev->bus->probe(dev);或drv->probe(dev)

4.2.1 Question: In the i2c_register_driver function, it is enough to call the driver_register(&driver->driver); function to add a driver. Why is it also called i2c_for_each_dev(driver, __process_new_driver);

When I was looking at the i2c_add_driver(&at24_driver) function, I found that calling the driver_register function actually completed the driver registration work. Next, I also called an i2c_for_each_dev(driver, __process_new_driver); for what purpose, and the inside of this function turned out to be i2c_do_add_adapter. I looked at the code again and found that the __process_new_driver function was not called.

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/* Can't register until after driver model init */
	if (WARN_ON(!is_registered))
		return -EAGAIN;

	/* add the driver to the list of i2c drivers in the driver core */
	driver->driver.owner = owner;
	driver->driver.bus = &i2c_bus_type;
	INIT_LIST_HEAD(&driver->clients);

	/* When registration returns, the driver core
	 * will have called probe() for all matching-but-unbound devices.
	 */
	res = driver_register(&driver->driver);
	if (res)
		return res;

	pr_debug("driver [%s] registered\n", driver->driver.name);

	/* Walk the adapters that are already present */
	i2c_for_each_dev(driver, __process_new_driver);

	return 0;
}

The reason is here,

static int __process_new_driver(struct device *dev, void *data)
{
	if (dev->type != &i2c_adapter_type)
		return 0;
	return i2c_do_add_adapter(data, to_i2c_adapter(dev));
}

There is a judgment here if (dev->type != &i2c_adapter_type), so the subsequent function is not called at all, and the problem is solved.

4.3 What does the probe function do?

When a device or driver is added, the match function in i2c_bus_type will be called. After match, the probe function in the driver will be called. Let's take a look at what the probe function in the driver does.

at24_probe 

    ....

    at24->nvmem_config.name = dev_name(&client->dev);

    at24->nvmem_config.dev = &client->dev;

    at24->nvmem_config.read_only = !writable;

    at24->nvmem_config.root_only = true;

    at24->nvmem_config.owner = THIS_MODULE;

    at24->nvmem_config.compat = true;

    at24->nvmem_config.base_dev = &client->dev;

    at24->nvmem_config.reg_read = at24_read;//read function

    at24->nvmem_config.reg_write = at24_write;//write function

    at24->nvmem_config.priv = at24;

    at24->nvmem_config.stride = 1;

    at24->nvmem_config.word_size = 1;

    at24->nvmem_config.size = chip.byte_len;

    at24->nvmem = nvmem_register(&at24->nvmem_config);

    ....      

        nvmem->id = rval;

         nvmem->owner = config->owner;

        nvmem->stride = config->stride;

        nvmem->word_size = config->word_size;

        nvmem->size = config->size;

        nvmem->dev.type = &nvmem_provider_type;

        nvmem->dev.bus = &nvmem_bus_type;//Pay attention to this place.

        nvmem->dev.parent = config->dev;

        nvmem->priv = config->priv;

        nvmem->reg_read = config->reg_read;

        nvmem->reg_write = config->reg_write;

        np = config->dev->of_node;

        nvmem->dev.of_node = np;

        rval = device_add(&nvmem->dev);//I have seen this device_add function many times before, and it is nothing more than the same thing.

            bus_add_device(dev);

            bus_probe_device(dev);

                device_initial_probe(dev);

                __device_attach(dev, true);

                    bus_for_each_drv(dev->bus, NULL, &data,__device_attach_driver);

                        __device_attach_driver

                            driver_match_device(drv, dev);

                                 return drv->bus->match ? drv->bus->match(dev, drv) : 1;

                             driver_probe_device(drv, dev);

                                  driver_probe_device(drv, dev);

                                       really_probe(dev, drv);

                                           dev->bus->probe(dev);或drv->probe(dev)

4.3.1 Question: Why are there match and probe in at24_probe?

My understanding is that the at24_probe function should be similar to the implementation of a file_operation structure, and then there are specific read and write functions. Isn’t that enough? But from the above process, we can see that the at24_probe function also calls the match and probe functions. OK, continue. Looking at the kernel code solves my confusion. . . . . . . .

First look at

static struct bus_type nvmem_bus_type = {
	.name		= "nvmem",
};

Then I found that the match function is not defined here, so the match function is empty, then return drv->bus->match? drv->bus->match(dev, drv): 1; Return 1 directly, and then call driver_probe_device( drv, dev); function,

static int really_probe(struct device *dev, struct device_driver *drv)
{
	...

	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}
    
    ...
}

If the dev->bus->probe call here is empty, then the probe function of the driver structure is called. Then I look for the nvmem driver structure in the kernel code and cannot find it. Then I ask for help from Bing AI.

 So

struct nvmem_device {
	const char		*name;
	struct module		*owner;
	struct device		dev;
	int			stride;
	int			word_size;
	int			ncells;
	int			id;
	int			users;
	size_t			size;
	bool			read_only;
	int			flags;
	struct bin_attribute	eeprom;
	struct device		*base_dev;
	nvmem_reg_read_t	reg_read;
	nvmem_reg_write_t	reg_write;
	void *priv;
};

 There is no probe function in it, so else if (drv->probe) is not valid either.

At this point, the I2C driver framework is actually finished. Let me briefly introduce other things related to the I2C driver.

5 i2c-tools

i2c-tools is a set of useful tools and a set of sample codes.

5.1 Why i2c-tools is a set of useful tools

Why is i2c-tools a set of useful tools? Because it implements the i2cdetect detection function, i2cget reading function, i2cset writing function, and i2ctransfer transmission function. We can use these commands to operate or debug I2C devices, such as 

5.2 Why i2c-tools is also a set of sample codes

Why is i2c-tools also a set of sample codes? For example, if you use the I2C bus for transmission, in ./tools/i2ctransfer.c, we can see its code implementation,

Then we can imitate his process to operate our own I2C devices. The specific implementation of the above function such as set_slave_addr is in ./tools/i2cbusses.c, and we need to include the ./tools/i2cbusses.c file when writing code.

If the SMBus bus is used for transmission, the sample code in i2cget.c and i2cset.c is as follows

 Then if we want to use the SMBus bus to operate our i2c device, we can imitate his code. For example, the specific implementation of the above i2c_smbus_access function is in the ./lib/smbus.c file, so when we write the code, we need to include ./ lib/smbus.c file.

For example, write a test program to read and write eeprom


#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
#include "i2cbusses.h"
#include <time.h>


/* ./at24c02 <i2c_bus_number> w "100ask.taobao.com"
 * ./at24c02 <i2c_bus_number> r
 */

int main(int argc, char **argv)
{
	unsigned char dev_addr = 0x50;
	unsigned char mem_addr = 0;
	unsigned char buf[32];

	int file;
	char filename[20];
	unsigned char *str;

	int ret;

	struct timespec req;
	
	if (argc != 3 && argc != 4)
	{
		printf("Usage:\n");
		printf("write eeprom: %s <i2c_bus_number> w string\n", argv[0]);
		printf("read  eeprom: %s <i2c_bus_number> r\n", argv[0]);
		return -1;
	}

	file = open_i2c_dev(argv[1][0]-'0', filename, sizeof(filename), 0);
	if (file < 0)
	{
		printf("can't open %s\n", filename);
		return -1;
	}

	if (set_slave_addr(file, dev_addr, 1))
	{
		printf("can't set_slave_addr\n");
		return -1;
	}

	if (argv[2][0] == 'w')
	{
		// write str: argv[3]
		str = argv[3];

		req.tv_sec  = 0;
		req.tv_nsec = 20000000; /* 20ms */
		
		while (*str)
		{
			// mem_addr, *str
			// mem_addr++, str++
			ret = i2c_smbus_write_byte_data(file, mem_addr, *str);
			if (ret)
			{
				printf("i2c_smbus_write_byte_data err\n");
				return -1;
			}
			// wait tWR(10ms)
			nanosleep(&req, NULL);
			
			mem_addr++;
			str++;
		}
		ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end char
		if (ret)
		{
			printf("i2c_smbus_write_byte_data err\n");
			return -1;
		}
	}
	else
	{
		// read
		ret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf);
		if (ret < 0)
		{
			printf("i2c_smbus_read_i2c_block_data err\n");
			return -1;
		}
		
		buf[31] = '\0';
		printf("get data: %s\n", buf);
	}
	
	return 0;
	
}

6 i2c_dev.c universal driver

i2c_dev.c is actually a universal driver or universal driver, which implements a

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

If we use the universal driver i2c_dev.c, then we do not need to add i2c_client and i2c_driver. Then we can directly operate the i2c controller at the application layer, and then communicate with the slave device mounted on the I2C bus, which is equivalent to operating The specific hardware timing is implemented in the application, requiring application developers to understand both the specific hardware operation timing and the I2C bus protocol. That is the direction of the red line drawing

7 GPIO analog I2C

Take a brief look at the ./Linux-4.9.88_just_for_read/drivers/i2c/busses/i2c-gpio.c file. Let’s start with the entry function.

static struct platform_driver i2c_gpio_driver = {
	.driver		= {
		.name	= "i2c-gpio",
		.of_match_table	= of_match_ptr(i2c_gpio_dt_ids),
	},
	.probe		= i2c_gpio_probe,
	.remove		= i2c_gpio_remove,
};
static int __init i2c_gpio_init(void)
{
	int ret;

	ret = platform_driver_register(&i2c_gpio_driver);
	if (ret)
		printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);

	return ret;
}

The function calling relationship is nothing more than the same thing 

i2c_gpio_init

    platform_driver_register

        __platform_driver_register

        drv->driver.owner = owner;

        drv->driver.bus = &platform_bus_type;

        drv->driver.probe = platform_drv_probe;

        drv->driver.remove = platform_drv_remove;

        drv->driver.shutdown = platform_drv_shutdown;

        driver_register(&drv->driver);

            bus_add_driver

                  driver_attach(drv);

                        __driver_attach

                            driver_match_device(drv, dev);

                                 drv->bus->match ? drv->bus->match(dev, drv) : 1;

                             driver_probe_device(drv, dev);

                                  really_probe(dev, drv);

                                      dev->bus->probe或drv->probe(dev)

After the match, call the i2c_gpio_probe function in the driver structure, and then first call the of_i2c_gpio_get_props function to get the gpio information and some properties from the device tree, that is, the frequency, the open drain setting, and then get the sda ​​pin, scl pin, and then according to from The value obtained in the device tree sets the adapter, and then registers the adapter with i2c_bit_add_numbered_bus, and then calls __i2c_bit_add_bus in i2c_bit_add_numbered_bus, sets the algo algorithm in it, and then add_adapter.

i2c_gpio_probe

    of_i2c_gpio_get_pins

    devm_gpio_request(&pdev->dev, sda_pin, "sda");

    devm_gpio_request(&pdev->dev, scl_pin, "scl");

    i2c_bit_add_numbered_bus(adap);

        __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);         

            adap->something = &i2c_bit_algo;

            adap->retries = 3;

            if (bit_adap->getscl == NULL)

                adap->quirks = &i2c_bit_quirk_no_clk_stretch;

            ret = add_adapter(adap);//add_adapter就是i2c_add_numbered_adapter

                I don’t want to look at the subsequent calls. I have analyzed the previous similar analysis many times.

8 Feynman learning method: So I recorded a learning video explaining the driver framework of the I2C subsystem.

8 minutes to explain the overall framework of the Linux kernel I2C driver_哔哩哔哩_bilibili

References :

Punctual Atomic Driver Development Manual

Teacher Wei Dongshan’s comprehensive learning video on driver development

Linux4.9.88 kernel source code

7. Platform device driver - [Wildfire] Embedded Linux driver development practical guide - based on i.MX6ULL series documents

Two ideas for I2C driver implementation (i2c-dev.c and i2c-core.c)

https://www.cnblogs.com/happybirthdaytoyou/p/13594060.html  

[I2C] General driver i2c-dev analysis_i2c_dev_init_ZHONGCAI0901's Blog-CSDN Blog

Detailed Explanation of the I2C Subsystem of the Linux Kernel - It's enough to read this article - Programmer Sought

https://www.cnblogs.com/burnk/p/17454052.html

Take you ten minutes to understand the Linux I2C software architecture_bilibili_bilibili

I2C——i2c_driver registration and probe detection function call process_i2c probe_lxllinux's Blog-CSDN Blog

The kernel's processing of the device tree __device_node is converted into platform_device_initcall_from_entry_Chen Hongwei's blog-CSDN blog  https://www.cnblogs.com/schips/p/linux_driver_device_node_to_platform_device.html

Linux device model device_add_Luzhou Zhuohu Chong's blog-CSDN blog

https://www.cnblogs.com/yangjiguang/p/6220600.html

i2c device addition, driver loading and device matching_Android i2c heart rate device addition_bruk_spp's blog-CSDN blog

[I2C] Linux I2C subsystem analysis_ZHONGCAI0901's blog-CSDN blog

Guess you like

Origin blog.csdn.net/u013171226/article/details/131761869