linux系统lcd驱动原理,Linux-2.6.20的LCD驱动分析(三)

本文深入解析S3C2410平台LCD驱动中的关键函数,包括s3c2410fb_init_registers、s3c2410fb_check_var、s3c2410fb_remove、s3c2410fb_suspend及s3c2410fb_resume等。通过具体代码解释了LCD驱动在初始化、检查、移除、挂起及恢复过程中的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三、解剖s3c2410fb_driver变量

s3c2410fb_driver变量有什么作用呢?在前面的2.2节提到了它的定义,从它的原型可以看出 s3c2410fb_driver是个platform_driver类型的变量,前面的几个小节提到了从platform_driver的名字可以看出它应该是platform_device的驱动类型。为了方便阅读,这里再贴一次s3c2410fb_driver的定义:

static struct platform_driver s3c2410fb_driver = {

.probe            = s3c2410fb_probe,

.remove          = s3c2410fb_remove,

.suspend  = s3c2410fb_suspend,

.resume          = s3c2410fb_resume,

.driver            = {

.name      = "s3c2410-lcd",

.owner    = THIS_MODULE,

},

};

从定义可以看出,该platform_device的驱动函数有s3c2410fb_probe, s3c2410fb_remove,s3c2410fb_suspend和s3c2410fb_suspend。.resource成员前面的章节有说明,.driver成员的值相信不用再说明了吧,再明白不过了。前面的章节,s3c2410fb_probe被比较详细的介绍,这节中的主要任务就是解释其他的几个函数。在解释他们之前,s3c2410fb_probe里面在该函数结尾的时候调用了几个函数没有说到,所以在这里补上。

3.1 s3c2410fb_probe余党

在s3c2410fb_probe中最好调用了s3c2410fb_init_registers和s3c2410fb_check_var函数,这里应该将他们交代清楚。很显然,s3c2410fb_init_registers是初始化相关寄存器。那么后者呢?这里先把 s3c2410fb_init_registers搞定再说。s3c2410fb_init_registers的定义与实现如下,先根据它的指向流程,一步一步解释:

static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)

{

unsigned long flags;

/* Initialise LCD with values from haret */

local_irq_save(flags);     /* 关闭中断,在关闭中断前,中断的当前状态被保存在flags中,对于关闭中断的函数,linux内核有很多种,可以查阅相关的资料。*/

/* modify the gpio(s) with interrupts set (bjd) */

/*下面的modify_gpio函数是修改处理器GPIO的工作模式,它的实现很简单,将第二个参数的值与第三个参数的反码按位与操作后,在写到第一个参数。这里的第一个参数实际就是硬件的GPIO控制器。*/

modify_gpio(S3C2410_GPCUP,  mach_info->gpcup,  mach_info->gpcup_mask);

modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);

modify_gpio(S3C2410_GPDUP,  mach_info->gpdup,  mach_info->gpdup_mask);

modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);

local_irq_restore(flags);  //使能中断,并恢复以前的状态

/*下面的几个writel函数开始初始化LCD控制寄存器,它的值就是我们在smdk2410_lcd_platdata(arch/arm/mach-s3c2410/mach-smdk2410.c)中regs域的值。*/

writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);

writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);

writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);

writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);

writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);

s3c2410fb_set_lcdaddr(fbi);    /*该函数的主要作用是让处理器的LCD控制器的三个地址寄存器指向正确的位置,这个位置就是LCD的缓冲区,详细的情况可以参见s3c2410的用户手册。*/

……

/* Enable video by setting the ENVID bit to 1 这里打开video,在s3c2410fb_probe中被关闭了,这里打开*/

fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;

writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);

return 0;

}

OK,s3c2410fb_init_registers就简单介绍到这里。下面看看 s3c2410fb_check_var函数要干些什么事,要说到这个函数,还得提到fb_var_screeninfo结构类型,与它对应的是 fb_fix_screeninfo结构类型。这两个类型分别代表了显示屏的属性信息,这些信息可以分为可变属性信息(如:颜色深度,分辨率等)和不可变的信息(如帧缓冲的其实地址)。既然fb_var_screeninfo表示了可变的属下信息,那么这些可变信息就应该有一定范围,否则显示就会出问题,所以s3c2410fb_check_var函数的功能就是要在LCD的帧缓冲驱动开始运行之前将这些值初始到合法的范围内。知道了 s3c2410fb_check_var要做什么,再去阅读s3c2410fb_check_var函数的代码就没什么问题了。

3.2 s3c2410fb_remove

从这里开始将解释s3c2410fb_driver中的其他几个函数。那么就从s3c2410fb_remove开刀吧!顾名思义该函数就该知道,它要将这个platform设备从系统中移除,可以推测它应该释放掉所有的资源,包括内存空间,中断线等等。还是按照惯例,在它的实现代码中一步步的解释。

static int s3c2410fb_remove(struct platform_device *pdev)

{

struct fb_info     *fbinfo = platform_get_drvdata(pdev);  /*该函数从platform_device中,到fb_info信息*/

struct s3c2410fb_info *info = fbinfo->par;  //得到私有数据

int irq;

s3c2410fb_stop_lcd(info);    //该函数停止LCD控制器,实现可以在s3c2410fb.c中找到

msleep(1); //休息以下,等待LCD停止

s3c2410fb_unmap_video_memory(info);   //该函数释放缓冲区

if (info->clk) {          //停止时钟

clk_disable(info->clk);

clk_put(info->clk);

info->clk = NULL;

}

irq = platform_get_irq(pdev, 0);     //得到中断线,以便释放

free_irq(irq,info);    //释放该中断

release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD); /* 释放内存空间 */

unregister_framebuffer(fbinfo);       //向内核注销该帧缓冲

return 0;

}

3.3 s3c2410fb_suspend与s3c2410fb_resume

在实际的设备,常常可以看到LCD在不需要的时候进入休眠状态,当需要使用的时候又开始工作,比如手机,在不需要的时候LCD就熄灭,当需要使用的时候 LCD又被点亮。从实际中可以看出这对函数非常重要。虽然他们很重要,但不一定很复杂,下面看看它们是怎么样实现的。

static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)

{

struct fb_info     *fbinfo = platform_get_drvdata(dev);  //这两条语句好面熟^_^

struct s3c2410fb_info *info = fbinfo->par;

s3c2410fb_stop_lcd(info);  //停止LCD

/* sleep before disabling the clock, we need to ensure

* the LCD DMA engine is not going to get back on the bus

* before the clock goes off again (bjd) */

msleep(1);  //等待一下,因为LCD停止需要一点时间

clk_disable(info->clk);  //关闭LCD的时钟

return 0;

}

^_^,下面的代码就不用解释了吧!

static int s3c2410fb_resume(struct platform_device *dev)

{

struct fb_info     *fbinfo = platform_get_drvdata(dev);

struct s3c2410fb_info *info = fbinfo->par;

clk_enable(info->clk);

msleep(1);

s3c2410fb_init_registers(info);

return 0;

}

OK,到现在为止,对于platform device的相关驱动就over了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值