http://blog.csdn.net/yongan1006/article/details/6729874
linux设备驱动关心总线、设备和驱动3个实体。总线会将设备和驱动绑定。一个现实的Linux设备和驱动通常都需要挂载在一种总线上。但是一些Soc中,它将外设控制器直接挂载到Soc内存空间,即CPU可以通过访问寄存器来控制它们。这些设备没有相应的实际总线。为解决这个问题,linux自定义了一种虚拟总线——platform。
n 相关概念定义
linux源码根目录中drivers/base/platform.c
有如下描述
struct device platform_bus = {
.bus_id = "platform",
};
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = PLATFORM_PM_OPS_PTR,
};
紧接着便是platform_bus_type总线和platform_bus设备的注册。
nt __init platform_bus_init(void)
{
int error;
error = device_register(&platform_bus);
if (error)
return error;
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
在源代码/include/linux/platform_device.h有如下定义
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
n lpc32xx相关
lpc32xx已有的平台设备/mach-lpc32xx/arch-lpc32xx.c
static struct platform_device* lpc32xx_devs[] __initdata = {
&serial_std_platform_device,
&serial_hspd_platform_device,
#if defined (CONFIG_RTC_DRV_LPC32XX)
&rtc_device,
#endif
#if defined(CONFIG_SPI_LPC32XX)
#if defined(CONFIG_MACH_LPC32XX_SSP0_ENABLE)
&ssp0_device,
#endif
#if defined(CONFIG_MACH_LPC32XX_SSP1_ENABLE)
&ssp1_device,
#endif
#endif
#if defined (CONFIG_MACH_LPC32XX_I2C0_ENABLE)
&i2c0_device,
#endif
#if defined (CONFIG_MACH_LPC32XX_I2C1_ENABLE)
&i2c1_device,
#endif
#if defined (CONFIG_MACH_LPC32XX_USBOTG_I2C_ENABLE)
&i2c2_device,
#endif
#if defined(CONFIG_MTD_NAND_SLC_LPC32XX)
&slc_nand_device,
#endif
#if defined(CONFIG_TOUCHSCREEN_LPC32XX)
&tsc_device,
#endif
#if defined(CONFIG_KEYBOARD_LPC32XX)
&kscan_device,
#endif
#if defined (CONFIG_LPC32XX_MII)
&net_device,
#endif
#if defined(CONFIG_USB_OHCI_HCD)
&ohci_device,
#endif
#if defined(CONFIG_LPC32XX_WATCHDOG)
&watchdog_device,
#endif
#if defined(CONFIG_USB_GADGET_LPC32XX)
&usbd_device,
#endif
};
在同一文件的__init lpc32xx_init ()又有如下描述
void __init lpc32xx_init (void)
{
……
platform_add_devices (lpc32xx_devs, ARRAY_SIZE (lpc32xx_devs));
……
}
platform_add_devices()函数是platform_device_register()的扩展版本。它通过循环调用platform_device_register()实现多个平台设备的注册。
因此像静态I/O映射一样,如果要增加平台设备只需要在BSP的板文件中增加platform_device的结构体描述,然后再将平台设备结构体指针加入到platform_device* lpc32xx_devs[] __initdata{}中即可。
因为在BSP的板文件中完成了相关平台设备的注册,所以在编写驱动程序时只需要注册相应的驱动就行。
n 驱动编写
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 (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct pm_ext_ops *pm;
struct device_driver driver;
};
这个结构体中,probe和 remove是必须实现的,其它的方法则和电源管理相关。大部情况下,设备驱动不提供 suspend_late和resume_early方法。resume和suspend一般是这样处理的:开关设备,开关时钟。
probe方法:在字符设备驱动中,申请设备号,cdev结构,初始化注册cdev等的工作可以放在这个里面来完成。
remove方法则完成和probe相反的工作。
在模块加载和卸载函数中,只需要注册或注销平台设备驱动。
由于在编写驱动时通常需要些有关于设备自身的一些信息。因而在描述平台设备时,最好将自己编写的设备结构描述指针赋值给plafform_device->dev->platform_data结构。