The platform device driver is based on the device bus driver model. It just further encapsulates device into platform_device and device_driver into platform_device_driver. The device bus driver model has been analyzed before. The registration process of device and device_driver and their hierarchical relationship in the sysfs file system will not be analyzed. This article focuses on the new additions to the platform device driver compared to the device bus driver model.
In the abstraction of the Linux device model, there is a class of devices called "Platform Devices", which the kernel describes as follows (Documentation/driver-model/platform.txt):
Platform devices are devices that typically appear as autonomous entities in the system. This includes legacy port-based devices and host bridges to peripheral buses, and most controllers integrated into system-on-chip platforms. What they usually have in common is direct addressing from a CPU bus. Rarely, a platform_device will be connected through a segment of some other kind of bus; but its registers will still be directly addressable.
In general, Platform devices include: port-based devices (no longer recommended, and are only retained for compatibility with old devices, legacy); bridge devices connected to physical buses; controllers integrated on the SOC platform; devices connected to other buses (rarely seen), and so on.
These devices have a basic feature: they can be directly addressed through the CPU bus (such as the "registers" commonly seen in embedded systems). Therefore, due to this commonality, the kernel further encapsulates these devices based on the device model (device and device_driver), abstracting the paltform bus, platform device and platform driver, so that driver developers can easily develop drivers for such devices.
It can be said that paltform devices are very important to Linux driver engineers, because most of the device drivers we write are to drive plaftom devices.
platform_bus_type
We know that in the device bus driver model, BUS is like a matchmaker. Through its match function, it matches the device registered in the bus with the driver. Then each different bus has its own match function. Let's take a look at platform_bus_type.
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
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);
/* match against the id table first */
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);
}
If id_table is defined in platform_device_driver, platform_match_id is called for matching
For example:
static struct platform_device_id s3c24xx_driver_ids[] = {
{
.name = "s3c2410-i2c",
.driver_data = TYPE_S3C2410,
}, {
.name = "s3c2440-i2c",
.driver_data = TYPE_S3C2440,
}, { },
};
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 const struct platform_device_id *platform_match_id(struct platform_device_id *id, struct platform_device *pdev)
{
while (id->name[0]) {
if (strcmp(pdev->name, id->name) == 0) {
pdev->id_entry = id;
return id;
}
id++;
}
return NULL;
}
Obviously, the role of platform_match_id is to traverse the entire Id_table array to find whether there is a platform_device->name with the same name. If there is, it returns this Platform_device_id. Using Id_table breaks the limitation of the original device bus driver model that a device can only be paired with one device_driver. Now a platform_device_driver can be paired with multiple platform_devices.
If not, it just compares platform_device_driver->name with platform_device->name. This is why teachers often say when writing platform device drivers, "Register the driver with the kernel. If there is a device with the same name, call the driver->probe function...."
The role of id in pletform_device:
if (pdev->id != -1) /* If it is not -1, number the name */
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else /* -1 is the name directly*/
dev_set_name(&pdev->dev, pdev->name);
platform_device encapsulated from device
struct platform_device {
const char * name;
you hand;
struct device dev;
u32 num_resources;
struct resource * resource;
struct platform_device_id *id_entry;
/* arch specific additions */
struct pdev_archdata archdata;
};
name, the name of the device. This name will be copied to dev.init_name when the device is registered.
dev, the real device, can find the entire platform_device through container_of and access other members, such as resource mentioned later
num_resources, resource, the resource description of the device, abstracted by the struct resource (include/linux/ioport.h) structure.
In Linux, system resources include I/O, Memory, Register, IRQ, DMA, Bus, etc. Most of these resources are exclusive and do not allow multiple devices to use them at the same time, so the Linux kernel provides some APIs for allocating and managing these resources.
When a device needs to use certain resources, it only needs to use struct resource to organize these resources (such as name, type, start and end address, etc.) and save them in the resource pointer of the device. Then, when probing the device, the device will call the resource management interface to allocate and use these resources. The kernel's resource management logic can determine whether these resources have been used, whether they can be used, etc.
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
static struct resource led_resource[] = { // parameters of jz2440, driver not tested
[0] = {
.start = 0x56000010,
.end = 0x56000010 + 8 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 5,
.end = 5,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device led_dev = {
.name = "myled", //The device name matches the driver
.id = -1,
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
.dev = {
.release = led_release,
//.devt = MKDEV(252, 1),
},
};
platform_device_driver packaged from device_driver
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
struct platform_device_id *id_table;
};
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}
The struct platform_driver structure is very similar to the struct device_driver. The platform_drv_probe, platform_drv_remove, and platform_drv_shutdown functions above are just slightly converted to call the probe, remove, and shutdown functions in platform_driver. Let's take a look at an example.
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);
return drv->probe(dev);
}
APIs provided by Platform Device
/* include/linux/platform_device.h */
extern int platform_device_register(struct platform_device *);
extern void platform_device_unregister(struct platform_device *);
extern void arch_setup_pdev_archdata(struct platform_device *);
extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
extern int platform_get_irq(struct platform_device *, unsigned int);
extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *);
extern int platform_get_irq_byname(struct platform_device *, const char *);
extern int platform_add_devices(struct platform_device **, int);
extern struct platform_device *platform_device_register_full(const struct platform_device_info *pdevinfo);
static inline struct platform_device *platform_device_register_resndata(
struct device *parent, const char *name, int id,
const struct resource *res, unsigned int num,
const void *data, size_t size)
static inline struct platform_device *platform_device_register_simple(
const char *name, int id,
const struct resource *res, unsigned int num)
static inline struct platform_device *platform_device_register_data(
struct device *parent, const char *name, int id,
const void *data, size_t size)
extern struct platform_device *platform_device_alloc(const char *name, int id);
extern int platform_device_add_resources(struct platform_device *pdev,
const struct resource *res,
unsigned int num);
extern int platform_device_add_data(struct platform_device *pdev,
const void *data, size_t size);
extern int platform_device_add(struct platform_device *pdev);
Previous article:Comprehensive analysis of the spi driver framework, from master driver to device driver
Next article:ALSA sound card 07_Analysis calling process_Study notes
Recommended ReadingLatest update time:2024-11-23 07:32
- Popular Resources
- Popular amplifiers
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- The first! National Automotive Chip Quality Inspection Center established
- BYD releases self-developed automotive chip using 4nm process, with a running score of up to 1.15 million
- GEODNET launches GEO-PULSE, a car GPS navigation device
- Should Chinese car companies develop their own high-computing chips?
- Infineon and Siemens combine embedded automotive software platform with microcontrollers to provide the necessary functions for next-generation SDVs
- Continental launches invisible biometric sensor display to monitor passengers' vital signs
- Evaluation report summary: Ultra-low power STM32U5 IoT exploration kit
- 【AT-START-F403A Review】Part 3: USB communication and mouse button simulation
- Design of LED emergency lighting controller based on MSP430
- Kan Kaili said that 3G is doomed to lose money and launching it now would go against four major interests (News playback)
- CPU (Computer) Load Monitor
- IoT architecture and five major communication protocols
- How NFC and RFID are used in the apparel industry
- Smart electricity opens the door to more efficient electricity use in homes and buildings
- Limitations of Flash_API for C2000 Series (28335) DSP
- MSP430 MCU GPIO Programming Tutorial