Tux
Communication
Mailing lists
Documentation
User Manual
Target board info.
Target chip info.
Support
Linux support
Bugzilla
Downloads
STLinux
Updates
Search
Google


The web
stlinux.com
Distribution Guide
Device drivers
Platform bus
ST Logo
Previous   Contents   Next


Platform bus

The platform bus is a generic part of the kernel. The aim of this is to isolate the device drivers from platform-dependant details, such as the address at which they are loaded or which interrupt they use. This makes it unnecessary to fill the driver code with #ifdefs for each platform.

The architecture specific or board specific code would declare a platform device similar to the following:

static struct resource magic_resources[] = {
[0] = {
.start = 0x43000600, /* Physical start address */
.end = 0x430007ff, /* Physical end address */
.flags = IORESOURCE_MEM, /* It is memory */
},
[1] = {
.start = 42, /* The IRQ number */
.flags = IORESOURCE_IRQ, /* It is an IRQ */
},
};
struct magic_data {
.clock=166000000;
.bug_workaround=1; };
static struct platform_device magic_device = {
.name = "magic",
.id = 0,
.num_resources = ARRAY_SIZE(magic_resources),
.resource = magic_resources,
.dev = {
.platform_data=&magic_data;
}
};

The device must be registered with a call to platform_device_register().

The actual device driver itself needs to register the driver, with a code fragment similar to that shown below:

static int __init magic_probe(struct device *dev) { 
struct platform_device *pdev=to_platform_device(dev);
struct resource *r;
struct magic_data * md = dev->platform_data;
int irq;
void *magic_dev_p;
r=platform_get_resource(pdev,IORESOURCE_MEM,0);
irq=platform_get_irq(pdev,0);
printk("magic starts at 0x%08lx,ends at 0x%08lx on irq %d\n",
r->start,r->end,irq);
printk("Clock frequency is %dMHz\n",md->clock/1000000);
magic_dev_p=ioremap(r->start,r->end - r->start +1);
request_mem_region(r->start,r->end - r->start + 1,"magic");
}
static struct device_driver magic_driver = {
.name = "magic",
.bus = &platform_bus_type,
.probe = magic_probe,
.remove = magic_remove,
};
static int __init magic_init(void) {
return driver_register(&magic_driver);
}
static void magic_cleanup(void) {
driver_unregister(&magic_driver);
}
module_init(magic_init);
module_exit(magic_cleanup);

Note that the association of the platform data to the driver is via the name of the device driver. The magic_probe() is called with the data in the platform declaration filled in. It can then use the correct platform helper functions to extract the relevant information, such as start address and IRQ, which can then be used to access the device.

The above example also illustrates how extra information can be passed to the driver by means of driver-specific private data. The board support layer fills in this information, which can then be used by the driver. In this example, the clock frequency of the block is passed in via a private structure. It is strongly recommended that this technique is used as it can drastically reduce the number of #ifdefs that can occur.

As shown, this method of constructing the device driver gives a very clear separation of the chip dependant elements and the actual driver. The device driver itself should not need modification to support a new chip which has the same device as an old chip but at a different physical address.

Previous   Contents   Next
Valid HTML 4.01! Last updated: 2005/09/29 14:43:17
© Copyright STMicroelectronics Limited, 2005
Printer