};
5. 帧缓冲设备作为平台设备
S3C2440的LCD控制器被集成在芯片的内部作为一个相对独立的单元,所以Linux把它看做是一个平台设备,故在内核代码/arch/arm/plat-s3c24xx/devs.c中定义有LCD相关的平台设备及资源,代码如下:
/* LCD Controller */
//LCD控制器的资源信息
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,//LCD中断
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,//标识为LCD中断
}
};
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
struct platform_device s3c_device_lcd = {
.name = 's3c2410-lcd',//作为平台设备的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
}
};
EXPORT_SYMBOL(s3c_device_lcd);//导出定义的LCD平台设备,好在mach-smdk2440.c的smdk2440_devices[]中添加到平台设备列表中
除此之外,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中定义有:
/* LCD driver info */
//LCD硬件的配置信息,注意这里我使用的LCD是NEC 3.5寸TFT屏,这些参数要根据具体的LCD屏进行设置
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
//这个地方的设置是配置LCD寄存器5,这些宏定义在regs-lcd.h中,计算后二进制为:111111111111,然后对照数据手册上LCDCON5的各位来看,注意是从右边开始
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
.type = S3C2410_LCDCON1_TFT,//TFT类型
/* NEC 3.5'' */
.width = 240,//屏幕宽度
.height = 320,//屏幕高度
//以下一些参数在上面的时序图分析中讲到过,各参数的值请跟据具体的LCD屏数据手册结合上面时序分析来设定
.pixclock = 100000,//像素时钟
.xres = 240,//水平可见的有效像素
.yres = 320,//垂直可见的有效像素
.bpp = 16,//色位模式
.left_margin = 19,//行切换,从同步到绘图之间的延迟
.right_margin = 36,//行切换,从绘图到同步之间的延迟
.hsync_len = 5,//水平同步的长度
.upper_margin = 1,//帧切换,从同步到绘图之间的延迟
.lower_margin = 5,//帧切换,从绘图到同步之间的延迟
.vsync_len = 1,//垂直同步的长度
};
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
.displays = &smdk2440_lcd_cfg,//应用上面定义的配置信息
.num_displays = 1,
.default_display = 0,
.gpccon = 0xaaaa555a,//将GPC0、GPC1配置成LEND和VCLK,将GPC8-15配置成VD0-7,其他配置成普通输出IO口
.gpccon_mask = 0xffffffff,
.gpcup = 0x0000ffff,//禁止GPIOC的上拉功能
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaaaaaaaa,//将GPD0-15配置成VD8-23
.gpdcon_mask = 0xffffffff,
.gpdup = 0x0000ffff,//禁止GPIOD的上拉功能
.gpdup_mask = 0xffffffff,
.lpcsel = 0x0,//这个是三星TFT屏的参数,这里不用
};
下面,我们再看一下在驱动中是如果引用 到s3c2410fb_mach_info结构体的(注意上面讲的是在内核中如何使用的)。在mach-smdk2440.c中有:
//S3C2440初始化函数
static void __init smdk2440_machine_init(void)
{
//调用该函数将上面定义的LCD硬件信息保存到平台数据中
s3c24xx_fb_set_platdata(&smdk2440_fb_info);
s3c_i2c0_set_platdata(NULL);
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
smdk_machine_init();
}
s3c24xx_fb_set_platdata定义在plat-s3c24xx/devs.c中:
void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
{
struct s3c2410fb_mach_info *npd;
npd = kmalloc(sizeof(*npd), GFP_KERNEL);
if (npd) {
memcpy(npd, pd, sizeof(*npd));
//这里就是将内核中定义的s3c2410fb_mach_info结构体数据保存到LCD平台数据中,所以在写驱动的时候就可以直接在平台数据中获取s3c2410fb_mach_info结构体的数据(即LCD各种参数信息)进行操作
s3c_device_lcd.dev.platform_data = npd;
} else {
printk(KERN_ERR 'no memory for LCD platform datan');
}
}
一个小知识:不知大家有没有留意,在平台设备驱动中,platform_data可以保存各自平台设备实例的数据,但这些数据的类型都是不同的,为什么都可以保存?这就要看看platform_data的定义,定义在/linux/device.h中,void *platform_data是一个void类型的指针,在Linux中void可保存任何数据类型。
上面平台驱动如何应用平台设备的数据以达到板与驱动分离的目地可有下图表示:
上一篇:S3C2440中的GPIO
下一篇:S3C2440 ARM芯片时钟
推荐阅读最新更新时间:2024-11-02 12:18
设计资源 培训 开发板 精华推荐
- MPC5567VBBOARDS: MPC5567 Vertical基础板
- EVAL-AD7995EBZ,用于 AD7995、4 通道、10 位 ADC 的评估板
- DC872A,基于 LTC4213 电子断路器的演示板
- EVB9512,使用 LAN9512 高速 USB 2.0 转 10/100 以太网集线器的评估板 客户
- AD8317-EVAL,AD8317 评估板,1MHz 至 10GHz,50dB 对数检测器/控制器
- OP495GSZ-REEL 3V低压差稳压器典型应用
- 【FOC】无刷电机驱动器ODrive AP1.0-DRV8303版
- LT3091ET7 低噪声单电感正负转换器的典型应用
- 使用 NXP Semiconductors 的 MC10XS6200EK 的参考设计
- LT8494HFE 锂离子电池至 12V、650kHz 低静态电流升压的典型应用电路