==== This article is the original site. You are welcome to reprint it! Reprinted please indicate the source: http://blog.csdn.net/yyplc====
Kernel version linux-2.6.30.4
I2C is a sub-system under bus in Linux. It consists of client driver, i2c-core core, I2C Adapter Driver, algorithm aglorithm. There are two I2C current adapters in the S3C2440. As the platform_device device, it is registered and added when the system starts. The following describes the implementation process of I2C (device, driver, bus.
// Fill in device resources
// Struct resource struct describes the physical resources of devices attached to the CPU bus.
//. Start: Start address of the I2C register;. End: end address of the I2C register;. Flag: description of the characteristics and characteristics of the device entity
static struct resource s3c_i2c_resource[] = {[0] = {//i2c-0.start = S3C_PA_IIC,.end = S3C_PA_IIC + SZ_4K - 1,.flags = IORESOURCE_MEM,},[1] = {//i2c-1 .start = IRQ_IIC,.end = IRQ_IIC,.flags = IORESOURCE_IRQ,},};
/I2C adapter data during initialization
static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {.flags = 0,.slave_addr = 0x10,.frequency = 100*1000,.sda_delay = 100, };
// Declare the I2C adapter as platform_device
struct platform_device s3c_device_i2c0 = {.name = "s3c2410-i2c",#ifdef CONFIG_S3C_DEV_I2C1.id = 0,#else.id = -1,#endif.num_resources = ARRAY_SIZE(s3c_i2c_resource),.resource = s3c_i2c_resource,};static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {.flags= 0,.slave_addr= 0x10,.frequency= 100*1000,.sda_delay= 100, };
// Add the I2C adapter:
static struct platform_device *smdk2440_devices[] __initdata = {...&s3c_device_i2c0,...};
// Add plat_from_data
Void _ init jx_i2c0_set_platdata (struct s3c2410_platform_i2c * PD) {struct s3c2410_platform_i2c * NPD; If (! PD) Pd = & default_i2c_data0; NPD = kmemdup (PD, sizeof (struct s3c2410_platform_i2c), gfp_kernel); If (! NPD) printk (kern_err "% s: no memory for Platform Data \ n", _ FUNC _); else if (! NPD-> pai_gpio) NPD-> pai_gpio = initi_i2c0_cfg_gpio; // configure the I2C pin to be set to initi_device_i2c0.dev.platform_data = NPD; // Mount plat_form_data}
// After the related structure is defined, register and add platform_device in smdk2440_machine_init ().
Static void _ init smdk2440_machine_init (void) {s3c24xx_fb_set_platdata (& smdk2440_fb_info); initi_i2c0_set_platdata (null );... // register and add platform_deviceplatform_add_devices (smdk2440_devices, array_size (smdk2440_devices ));...}
Smdk2440_machine_init is assigned to machine_start.
It is called when start_kernel () --> setup_arch (), but it is worth noting that the I2C adapter is not initialized because there is no driver!
We can see the difference between platform_device_register () and device_register () through the following:
platform_add_devices()-->platform_device_register()-->platform_device_add()--> device-->add()
Platfrom_bus_init () will also add a device named platform (struct device platform_bus ):
plat_form_bus_init()-->device_register()-->device_register()-->device-->add()
However, this device is virtual. All devices after platform_device_add () are under/devices/platform /.
Because all plaform_device's parents are platform_bus, they are in platform_device_add ().
if (!pdev->dev.parent)pdev->dev.parent = &platform_bus;
I think this is the difference between platform_device_register () and device_register ().
In reset_init () --> kernel_init () --> do_basic_setup ()
--> Driver_init () --> platform_bus_init () to register the platform_bus
However, the I2C adapter is not bound to the driver, because the driver has not yet appeared (initialization)
The I2C Adapter driver can be initialized only by preparing for the previous steps.
S3c2440-i2c Adapter driver initialization is implemented in drivers/I2C/bus/i2c-s3c2410.c
And register as platform_driver.
// Fill in the driver structure and complete functions such as probe and remove
static struct platform_driver s3c2440_i2c_driver = {.probe = s3c24xx_i2c_probe,.remove = s3c24xx_i2c_remove,.suspend_late = s3c24xx_i2c_suspend_late,.resume = s3c24xx_i2c_resume,.driver = {.owner = THIS_MODULE,.name = "s3c2440-i2c", //},};
// Initialize and register platform_driver
static int __init i2c_adap_s3c_init(void){int ret;ret = platform_driver_register(&s3c2410_i2c_driver);//if (ret == 0) {printk("register s3c2440_i2c_driver.....\n");ret = platform_driver_register(&s3c2440_i2c_driver);if (ret){printk("register s3c2410_i2c_driver.....\n");platform_driver_unregister(&s3c2410_i2c_driver);}}return ret;}subsys_initcall(i2c_adap_s3c_init);
In this way, the adapter is bound to the driver. The process is as follows:
platform_driver_register()-->driver_register()-->bus_add_driver()-->driver_attach()__driver_attach()-->driver_probe_device()-->s3c24xx_i2c_probe()
In addition, it is called when s3c24xx_i2c_probe ()
i2c_add_numbered_adapter(&i2c->adap);
Finally, add an adapter that is itself an I2C bus. The analysis process ends.