從linux 2.6起引入了新一套的驅動管理和註冊機制:platform_device 和piatform_driver. (platform表明平臺);設備用platform_device表示,驅動用piatform_driver進行註冊。 linux
Linuxplatformdriver機制和傳統的devicedriver機制(經過driver_register函數進行註冊)相比,一個十分明顯的優點在於platform機制將設備自己的資源註冊進內核,由內核統一管理,在驅動程序中使用這些資源時經過platformdevice提供的標準接口進行申請並使用。這樣提升了驅動和資源管理的獨立性,而且擁有較好的可移植性和安全性(這些標準接口是安全的)。 安全
Platform機制的自己使用並不複雜,由兩部分組成:platform_device和platfrom_driver。 ide
經過Platform機制開發底層驅動的大體流程爲:定義resoucre->定義platform_device->定義platform_driver->註冊platform_driver。 函數
內核裏已經有很完善的lcd驅動了,咱們只要根據所用的LCD進行簡單的修改。 首先要確認的就是設備的資源信息,例如設備的地址,中斷號等。 指針
在2.6內核中platform設備用結構體platform_device來描述,該結構體定義在orm
kernel\include\linux\platform_device.h 接口
中。 資源
Struct platform_device{ 開發
const char *name; u32 id; get
struct device dev; u32 num_resources;
struct resource *resource;
};
該結構一個重要的元素是resource,該元素存入了最爲重要的設備資源信息,定義在
kernel\include\linux\ioport.h中。 struct resource{
resource_size_tstart; //描述設備實體在cpu總線上的線性起始物理地址;
resource_size_tend; // 描述設備實體在cpu總線上的線性結尾物理地址;
const char *name; // 描述這個設備實體的名稱,這個名字開發人員能夠隨意起;
unsigned long flags; //描述這個設備實體的一些共性和特性的標誌位; (標示爲LCD控制器IO端口,在驅動中引用這個就表示
引用IO端口)
struct resource *parent, *sibling, *child;// 指針parent、sibling和child:分別爲
指向父親、兄弟和子資源的指針。
};
例如:
一、修改linux-2.6.32.2\arch\arm\palt-s3c24xx\devs.c文件:添加平臺設備LCD佔用的資源。 打開devs.c
/* LCD Controller */
static struct resource s3c_lcd_resource[ ] = {
[0] = { .start = S3C24XX_PA_LCD, //(控制器IO端口開始地址)
.end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,//(控制器IO端口結束地址)
.flags = IORESOURCE_MEM, //(標示爲LCD控制器IO端口,在驅動中引用這個
就表示引用IO端口)
}, [1] = { .start = IRQ_LCD, .end = IRQ_LCD, .flags = IORESOURCE_IRQ, } };
有了resource信息,就能夠定義platform_device了:
二、修改linux-2.6.32.2\arch\arm\plat-s3c24xx\devs.c文件:添加平臺設備s3c_devce_lcd。以下所示,若是已經有則不用添加。
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
struct platform_device s3c_device_lcd = { .name = "s3c2410-lcd", .id = -1, .num_resources = ARRAY_SIZE(s3c_lcd_resource), .resource = s3c_lcd_resource, .dev = { .dma_mask = &s3c_device_lcd_dmamask, .coherent_dma_mask = 0xffffffffUL } };
這裏是定義一個本身的設備的一些信息。定義好了platform_device結構體後就能夠調用函數platform_add_devices向系統中添加該設備了,以後能夠調用platform_device_register()進行設備註冊。當註冊成功時會調用platform_driver結構元素probe函數指針,這裏
就是s3c24xx_i2c_probe,當進入probe函數後,須要獲取設備的資源信息,經常使用獲取資源的函數主要是:
struct resource *platform_get_resource ( struct platform_device *dev, unsigned int type, unsigned int num);
根據參數type所指定類型,例如IORESOURCE_MEM,來獲取指定的資源。
struct int platform_get_irq (struct platform_device *dev,unsigned int num);//獲取資源中的中斷號。(這裏能夠不看)導出定義的LCD平臺設備,好在mach-smdk2440.c的smdk2440_devices[]中添加到平臺設備列表。
EXPORT_SYMBOL(s3c_device_lcd);
(linux還在/arch/arm/mach-s3c2410/include/mach/fb.h)中爲LCD平臺設備定義了一個s3c2410fb_mach_info結構體,該結構體主要是記錄LCD的硬件參數信息(好比該結構體的s3c2410fb_display成員結構中就用於記錄LCD的屏幕尺寸、屏幕信息、可變的屏幕參數、LCD配置寄存器等),這樣在寫驅動的時候就直接使用這個結構體。下面,咱們來看一下內
核是如何使用這個結構體的。在/arch/arm/mach-s3c2440/mach-smdk2440.c(這裏看本身定義的文件個人爲mach-mini2440.c之後我就用mini2440);
3. 修改arch\arm\mach-s3c2440\mach-smdk2440.c:配置s3c2440_devices平臺設備數據,註冊s3c2440_devices平臺設備。
static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd,(前面第二步已經定義了這個結構體了) &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &s3c_device_nand, &mini2440_device_eth,
};
4. 修改arch\arm\mach-s3c2440\mach-mini2440.c:配置mini2440_devices_lcd平臺設備數據。 /* LCD driver info */
static struct s3c2410fb_display mini2440_lcd_cfg __initdata = { #if !defined (LCD_CON5) .lcdcon5 = S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_PWREN | S3C2410_LCDCON5_HWSWP, #else .lcdcon5 = LCD_CON5, #endif .type = S3C2410_LCDCON1_TFT, .width = LCD_WIDTH, .height = LCD_HEIGHT, .pixclock =LCD_PIXCLOCK, /* HCLK 60 MHz, divisor 10 */ .xres = LCD_WIDTH, .yres =LCD_HEIGHT, .bpp = 16, .left_margin = LCD_LEFT_MARGIN +1, .right_margin =LCD_RIGHT_MARGIN +1, .hsync_len = LCD_HSYNC_LEN+1, .upper_margin = LCD_UPPER_MARGIN+1, .lower_margin = LCD_LOWER_MARGIN+1, .vsync_len =LCD_VSYNC_LEN+1 , };
5. 修改mach-mini2440.c添加X35屏支持。(這一部分要放在第四步的前面) #define LCD_WIDTH 240 //屏寬 #define LCD_HEIGHT 320 //屏高
#define LCD_PIXCLOCK 170000 //時鐘 #define LCD_RIGHT_MARGIN 25 //左邊界
#define LCD_LEFT_MARGIN 0 //右邊界 #define LCD_HSYNC_LEN 4 //行同步 #define LCD_UPPER_MARGIN 0 //上邊界 #define LCD_LOWER_MARGIN 4 //下邊界 #define LCD_VSYNC_LEN 9 //幀同步
#define LCD_CON5 (S3C2410_LCDCON5_FRM565 | \ S3C2410_LCDCON5_INVVFRAME | \ S3C2410_LCDCON5_INVVLINE | \ S3C2410_LCDCON5_INVVFRAME | \ S3C2410_LCDCON5_INVVDEN | \ S3C2410_LCDCON5_PWREN | \ S3C2410_LCDCON5_BSWP )
6. 修改arch\arm\mach-s3c2440\mach-mini2440.c:配置s3c2440_devices平臺設備數據,註冊s3c2440_devices平臺設備,加LCD背光
(由於mini2440的3.5英寸液晶顯示屏的背光是由s3c2440的GPG4引腳來控制的,) static struct s3c2410fb_mach_info mini2440_fb_info __initdata ={ .displays = &mini2440_lcd_cfg,// (第5步已經設置過mini2440_lcd_cfg) .num_displays = 1, .default_display = 0,//(註釋:default爲未履行的) .gpccon= 0xaa955699, .gpccon_mask= 0xffc003cc, .gpcup= 0x0000ffff, .gpcup_mask= 0xffffffff, .gpdcon= 0xaa95aaa1, .gpdcon_mask= 0xffc0fff0, .gpdup= 0x0000faff, .gpdup_mask= 0xffffffff, .lpcsel =0xf82, };
static void __init mini2440_machine_init(void) {
s3c24xx_fb_set_platdata(&mini2440_fb_info); (設置s3c2440_devices平臺設備數據)
s3c_i2c0_set_platdata(NULL);
s3c2410_gpio_cfgpin(S3C2410_GPG(4),S3C2410_GPIO_OUTPUT);(配置lcd管腳)(要添加 #include<linux/gpio.h> )
s3c2410_gpio_setpin(S3C2410_GPG(4),1);
s3c_device_nand.dev.platform_data = &mini2440_nand_info;
//s3c_device_sdi.dev.platform_data=&s3c2410_mmc_cfg;
platform_add_devices (mini2440_devices, ARRAY_SIZE(mini2440_devices));(將LCD平臺設備註冊到內核)
//s3c_pm_init();
//mini2440_machine_init();(這些用不到的能夠屏蔽掉) }
7. 修改inux-2.6.32.2/drivers/video/Kconfig文件. config FB_S3C2410_X240320
boolean"3.5 inch 240X320 SONY LCD (X35-ACX502BMU) " depends on FB_S3C2410 help
3.5 inch 240X320 SONY LCD (X35-ACX502BMU) 8.make menuconfig Device Driver:
<*>support for frame buffer devices - [* ] Enable frameware EDID
[* ] Enable Vidoe Mode Handling Helpers <*>S3C24X0 LCD framebuffer support Console display driver support -- <*> Framebuffer Console Support [* ] Bootup Logo --
<*> Standard 224-color Linux logo 最後啓動內核後就能夠看見企鵝了。