Linux platform device and driver, platform_add_devices ()-> platform_driver_register ()

Source: Internet
Author: User
Linux platform device and driver, platform_add_devices ()-> platform_driver_register () Favorites Http://blog.csdn.net/lanmanck/archive/2009/08/17/4455692.aspx

From: http://www.diybl.com/course/6_system/linux/Linuxjs/200871/129585.html

A new driver management and registration mechanism has been introduced since Linux 2.6: platform_device and platform_driver.

Most device drivers in Linux can use this mechanism. The device is represented by platform_device and the driver is registered by platform_driver.

Compared with the traditional device driver mechanism (registered through the driver_register function), the Linux platform driver mechanism has a significant advantage in registering the resources of the device into the kernel, centrally managed by the kernel and drivenProgramUse the standard interfaces provided by platform device to apply for and use these resources. This improves the independence of drivers and resource management, and provides good portability and Security (these standard interfaces are secure ).

The use of the platform mechanism is not complex and consists of two parts: platform_device and platfrom_driver.

The general process for developing the underlying driver through the platform mechanism is: Define platform_device-> Register platform_device-> define platform_driver-> Register platform_driver.

The first thing to confirm is the device resource information, such as the device address and interrupt number.

In the 2.6 kernel, the platform device is described by the structure platform_device, which is defined in kernel \ include \ Linux \ platform_device.h,

Struct platform_device {

Const char * Name;

U32 ID;

Struct device dev;

U32 num_resources;

Struct resource * resource;

};

An important element of this structure is resource, which stores the most important device resource information and is defined in kernel \ include \ Linux \ ioport. h,

Struct resource {

Const char * Name;

Unsigned long start, end;

Unsigned long flags;

Struct resource * parent, * sibling, * child;

};

The following describes the I2C driver of the S3C2410 platform as an example:

/* ARCH/ARM/mach-s3c2410/Devs. C */
/* I2C */
Static struct resource initi_i2c_resource [] = {
[0] = {
. Start = s3c24xx_pa_iic,
. End = s3c24xx_pa_iic + s3c24xx_sz_iic-1,
. Flags = ioresource_mem,
},
[1] = {
. Start = irq_iic, // s3c2410_irq (27)
. End = irq_iic,
. Flags = ioresource_irq,
}
};

Two groups of resources are defined here, which describe the resources of an I2C device, and 1st describe the BUS address range occupied by this I2C device, ioresource_mem indicates that the 1st group describes the memory-type resource information, the 2nd group describes the interrupt Number of the I2C device, and the ioresource_irq indicates that the 2nd group describes the interrupted resource information. The device driver obtains the corresponding resource information based on flags.

With the resource information, you can define platform_device:

Struct platform_device initi_device_i2c = {
. Name = "s3c2410-i2c ",
. ID =-1,
. Num_resources = array_size (cloud_i2c_resource ),
. Resource = maid resource,
};

After the platform_device struct is defined, you can call the platform_add_devices function to add the device to the system. Then, you can call platform_device_register () to register the device. Note that the registration process of the platform_device must be called before the driver of the device is loaded, that is, before platform_driver_register is executed, the reason is that the device name already registered in the kernel needs to be matched during driver registration.

The platform_device of the s3c2410-i2c is at system startup, at CPU. c. This function is registered in the initialization phase of the system.

Arch_initcall has a higher priority than module_init. So it will be called before the platform driver registration. (For details, see include/Linux/init. h)

The following table lists the functions of the initial_arch_init function:

/* ARCH/ARM/mach-3sc2410/CPU. C */
static int _ init initi_arch_init (void)
{< br> int ret;
......
/* here the Board Pointer Points to the smdk2410_board defined in the mach-smdk2410.c, which contains pre-defined I2C platform_device and so on. */
If (board! = NULL) {
struct platform_device ** PTR = Board-> devices;
int I;
for (I = 0; I devices_count; I ++, PTR ++) {
ret = platform_device_register (* PTR); // register here
If (RET) {
printk (kern_err "s3c24xx: failed to add board Device % s (% d) @ % P \ n", (* PTR)-> name,
ret, * PTR);
}< BR >}< br>/* mask any error, we may not need all these Board
* devices */
ret = 0;
}< br> return ret;
}< br>

Also registered with many other platform platform_device, details of the arch/ARM/mach-s3c2410/mach-smdk2410.c in the smdk2410_devices struct.

The driver must implement the struct platform_driver. For details, see drivers/I2C/busses.

/* Device Driver for platform bus bits */


Static struct platform_driver s3c2410_i2c_driver = {
. Probe = s3c24xx_i2c_probe,
. Remove = s3c24xx_i2c_remove,
. Resume = s3c24xx_i2c_resume,
. Driver = {
. Owner = this_module,
. Name = "s3c2410-i2c ",
},
};

Call the platform_driver_register () function in the driver initialization function to register the platform_driver. Note that the name element and the driver in the s3c2410_i2c_driver structure are the names of the parameters in the initialized_drivers structure. the name must be the same. In this way, when platform_driver_register () is registered, the name of all registered platform_device and the driver of the currently registered platform_driver will be used. name for comparison. Only platfomr_device with the same name can be successfully registered. when the registration is successful, the probe function pointer of the platform_driver structure element will be called. This is s3c24xx_i2c_probe. after entering the probe function, the following functions are commonly used to obtain device Resource Information:

Struct resource * platform_get_resource (struct platform_device * Dev, unsigned int type, unsigned int num );

Obtain the specified Resource Based on the type specified by the parameter, such as ioresource_mem.

Struct int platform_get_irq (struct platform_device * Dev, unsigned int num );

Gets the interrupt number in the resource.

The following shows the analysis of the s3c24xx_i2c_probe function to see how these interfaces are used.

As mentioned above, after the registration of the s3c2410_i2c_driver is successful, the s3c24xx_i2c_probe command will be called for execution. See the following:Code:

/* S3c24xx_i2c_probe
*
* Called by the bus driver when a suitable device is found
*/

/* Drivers/I2C/busses/i2c-s3c2410.c */
Static int s3c24xx_i2c_probe (struct platform_device * pdev)
{
Struct s3c24xx_i2c * I2C = & s3c24xx_i2c;
Struct resource * res;
Int ret;
/* Find the clock and enable it */
I2C-> Dev = & pdev-> dev;
I2C-> CLK = clk_get (& pdev-> Dev, "I2C ");
If (is_err (I2C-> CLK )){
Dev_err (& pdev-> Dev, "cannot get clock \ n ");
Ret =-enoent;
Goto out;
}
Dev_dbg (& pdev-> Dev, "clock source % P \ n", I2C-> CLK );
Clk_enable (I2C-> CLK );


/* Map the registers */
Res = platform_get_resource (pdev, ioresource_mem, 0);/* get the device's IO resource address */
If (RES = NULL ){
Dev_err (& pdev-> Dev, "cannot find IO resource \ n ");
Ret =-enoent;
Goto out;
}
I2C-> ioarea = request_mem_region (res-> Start, (res-> end-res-> Start) + 1, pdev-> name);/* apply for this Io Region */
If (I2C-> ioarea = NULL ){
Dev_err (& pdev-> Dev, "cannot request IO \ n ");
Ret =-enxio;
Goto out;
}
I2C-> regs = ioremap (res-> Start, (res-> end-res-> Start) + 1);/* ing to kernel virtual space */
If (I2C-> regs = NULL ){
Dev_err (& pdev-> Dev, "cannot map IO \ n ");
Ret =-enxio;
Goto out;
}
Dev_dbg (& pdev-> Dev, "registers % P (% P, % P) \ n", I2C-> regs, I2C-> ioarea, Res );
/* Setup info block for the I2C core */
I2C-> ADAP. algo_data = I2C;
I2C-> ADAP. Dev. Parent = & pdev-> dev;
/* Initialise the I2C controller */
Ret = s3c24xx_i2c_init (I2C );
If (Ret! = 0)
Goto out;
/* Find the IRQ for this unit (note, this relies on the init call to ensure no current irqs pending */
Res = platform_get_resource (pdev, ioresource_irq, 0);/* get the device IRQ interrupt Number */
If (RES = NULL ){
Dev_err (& pdev-> Dev, "cannot find IRQ \ n ");
Ret =-enoent;
Goto out;
}
Ret = request_irq (res-> Start, s3c24xx_i2c_irq, ir1__disabled,/* apply for IRQ */
Pdev-> name, I2C );
......
Return ret;
}

TIPS:

In what cases can we use the platform driver mechanism to write a driver?

My understanding is that as long as the peripheral device is not dependent on the kernel itself (in other words, as long as it is not within the minimum system required for the kernel operation), it is relatively independent, with their own resources (addresses and irqs), you can use platform_driver. For example, LCD, USB, UART, and so on can all be written using platfrom_driver, while it is better to use the platfrom_driver mechanism for devices in the smallest system such as timer and IRQ. In fact, the kernel implementation is also like this.

References:

Linux-2.6.24/documentation/driver-model/platform.txt

Platform _ device and platform_driver registration process

Http://blog.chinaunix.net/u2/60011/showart.php? Id = 1018999

Http://www.eetop.cn/blog/html/45/11145-676.html

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.