LCD背光驱动 --Backlight

来源:互联网 发布:网络数据线 编辑:程序博客网 时间:2024/05/01 10:12

       显示屏按其显示原理大致可分为CRT(显像管)、LCD(液晶)及OLED三类,从市场应用看,手机中使用的显示屏主流是LCD,OLED只在翻盖机的小屏中占有少量份额,而CRT在手机中没有用到。
       LCD本身不会发光,要想让其显示所要数据和图像,就必需使用白光背光源,手机中的白光背光源一般由数个侧发光白色LED灯组成,LED灯的个数由屏的大小尺寸决定,一般由2~6个不等。

 

【1】LCD 背光控制原理

在 fl2440开发板中,LCD 背光是通过CPU 的LCD_PWR 引脚来控制的,从原理图中可以看出,它对应于GPG4,如图

Linux-2.6.32.2内核在mini2440上的移植(六)---添加LCD背光驱动 - singleboy - singleboy的博客

当LCD_PWR 输出为高电平“1”时,将打开背光;当输出为低电平“0”时,将关闭背光(注意:这里只是打开和关闭背光,而并没有背光亮度的调节作用)。

【2】 在内核中添加背光驱动程序

现在,我们需要增加一个简单的背光驱动,以便能够通过软件便可简单的控制背光的开关。我们要达到的目的是:在命令终端通过向背光设备发送偶数比如“0”便可关闭背光,发送奇数比如“1”便可打开背光,这样使用起来就方便多了,而不需要专门的应用程序控制它,正如在用户手册中所描述的方法(2.5.10 控制LCD 的背光):
提示:LCD 背光设备文件:/dev/backlight
在命令行种输入:echo 0 > /dev/backlight 可以关闭LCD 背光。
在命令行种输入:echo 1 > /dev/backlight 可以打开LCD 背光。
为了实现这点,我们在drivers/video/backlight 目录增加一个fl2440_backlight.c文件,内容如下:

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#include <mach/gpio.h>
#define DEVICE_NAME "backlight" //设备名称
#define DEVICE_MINOR 255 //次设备号自动申请,这里我们将设备注册为misc设备,这种设备的主设备号都为10

#define S3C2410_GPG4  S3C2410_GPG(4)
#define S3C2410_GPG4_OUTP  (0x01 << 8)

static long fl2440_backlight_ioctl(struct file *file,
                                  unsigned int cmd,
                                  unsigned long arg)
{
   switch(cmd)
     {
        case 0:

            //当接收的命令为0时,就将GPG4引脚设为低电平,关闭背光
            s3c2410_gpio_setpin(S3C2410_GPG4, 0);
            printk(DEVICE_NAME " turn off!\n");
            return 0;
        case 1:

            //当接收的命令为1时,就将GPG4引脚设为高电平,开启背光
            s3c2410_gpio_setpin(S3C2410_GPG4, 1);
            printk(DEVICE_NAME " turn on!\n");
            return 0;
        default:
            return -EINVAL;
     }
}

static struct file_operations dev_fops =
{
    .owner = THIS_MODULE,
    .unlocked_ioctl = fl2440_backlight_ioctl, //这里只使用控制IO口的方式来控制背光
};

static struct miscdevice misc =
{
    .minor = DEVICE_MINOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops,
};

static int __init dev_init(void)
{
   int ret;
   ret = misc_register(&misc); //注册成misc设备
   if(ret < 0)
     {
        printk("Register misc device fiald!");
        return ret;
     }

     //将GPG4口配置成输出口,默认为点亮
    s3c2410_gpio_cfgpin(S3C2410_GPG4, S3C2410_GPG4_OUTP);
    s3c2410_gpio_setpin(S3C2410_GPG4, 1);
    return ret;
}

static void __exit dev_exit(void)
{
    misc_deregister(&misc); //注销该misc设备
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("smart.zhao");
MODULE_DESCRIPTION("Backlight control for fl2440");

 

【3】把背光配置选项加入内核配置菜单

打开drivers/video/backlight/Kconfig,定位到1929行附近,加入如下代码:

#
# Backlight & LCD drivers configuration
#

menuconfig BACKLIGHT_LCD_SUPPORT
bool "Backlight & LCD device support"
help
Enable this to be able to choose the drivers for controlling the
backlight and the LCD panel on some platforms, for example on PDAs.

if BACKLIGHT_LCD_SUPPORT

 

config BACKLIGHT_FL2440
 tristate "Backlight support for FL2440 from FriendlyARM"
 depends on BACKLIGHT_LCD_SUPPORT
 help
 backlight driver for FL2440 from FriendlyARM

#
# LCD
#
config LCD_CLASS_DEVICE

 

再打开 drivers/video/backlight/Makefile,定位到文件末尾,根据配置定义加入驱动目标文件,如下:

obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o
obj-$(CONFIG_BACKLIGHT_FL2440)  += fl2440_backlight.o

【4】在内核配置菜单中确认 "Backlight support for mini2440 from FriendlyARM"被选中。

在内核源代码根目录执行:
make menuconfig,依次选择如下子菜单:

Device Drivers --->
Graphics support --->
[*] Backlight & LCD device support --->

就可以找到该配置选项,如图

 

linux 3.1内核的驱动路(5)--添加LCD背光驱动 - Smart_zhao - 军惠博客

在这里,如果没有被选中,按空格选中我们刚刚加入的mini2440 配置项,然后退出时保存内核配置菜单,在命令行执行:make uImage

将生成的arch/arm/boot/uImage复制到/nfsboot目录下,然后启动开发板,可以在启动时看到LCD屏显示的企鹅图像,这说明我们已经点亮了背光。

 

【5】编写测试程序linux-test/codetest/backlight_test.c,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>

int main(int argc, char **argv)
{
int turn;
int fd;

//检测命令后面带的参数
if(argc == 1 || argc > 2)
{
printf("Usage: backlight_test on|off!\n");
exit(1);
}

//打开背光设备
fd = open("/dev/backlight", O_RDWR);

if(fd < 0)
{
printf("Open Backlight Device Faild!\n");
exit(1);
}

//判断输入的参数
if(strcmp(argv[1], "on") == 0)
{
turn = 1;
}
else if(strcmp(argv[1], "off") == 0)
{
turn = 0;
}
else
{
printf("Usage: backlight_test on|off!\n");
exit(1);
}

//进行IO控制
ioctl(fd, turn);

//关闭背光设备
close(fd);

return 0;
}
编译程序,测试结果如下:

linux 3.1内核的驱动路(5)--添加LCD背光驱动 - Smart_zhao - 军惠博客

 

ANDROID里,自带的背光亮度调节,会调用哪个接口?

会调用

/sys/class/leds/lcd-backlight/brightness

而这个brightness节点,是如何声明的呢

请看LED驱动里的这么一句

static DEVICE_ATTR(brightness, /*NAME*/

0644, /*权限*/

led_brightness_show, /*Read Point*/

led_brightness_store); /*Write Point*/

这就是声明brightness的。

这里调用了led_brightness_store做为写背光函数,也就是调节时用到,它最终会调用到显示驱动里的PWM操作函数,实现背光调节。

分析:

在LED驱动中,led_classdev_register ()函数,调用device_create()创建了操作结构体空间leds_class,

led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,"%s", led_cdev->name);

关键是填充led_cdev结构体。

在led_brightness_store函数里,调用led_set_brightness设置背光亮度,最终是调用了

led_cdev->brightness_set(led_cdev, value);实现操作,这个操作,会调用哪里的函数呢?它是显示驱动里的brightness_set()函数。

请注意看,在显示驱动里(S3cfb_lte480wv.c),有这么一段代码,

static struct led_classdev smdk_backlight_led = {

.name = "lcd-backlight",

.brightness = SMDK_DEFAULT_BACKLIGHT_BRIGHTNESS,

.brightness_set = smdk_brightness_set,

};

把brightness_set指向了smdk_brightness_set()函数。这就有戏看了,终于找到真正操作函数了。

当然,LED驱动是如何与显示驱动关联起来的,这一套机制,得看一下

static int smdk_bl_probe(struct platform_device *pdev)

{

led_classdev_register(&pdev->dev, &smdk_backlight_led);

return 0;

}

原来使用了led_classdev_register(),它是由LEDS驱动提供的函数,

#include 传过来的。

这就把smdk_backlight_led 结构体指针传给了LEDS驱动,里面就有smdk_brightness_set函数的指针,所以,LEDS里的led_cdev->brightness_set能调用到这边来,呵呵。原来是这样。

注册背光的控制节点

/sys/class/leds/lcd-backlight/brightness

是在这个函数 platform_driver_register() à

smdk_bl_probe() à led_classdev_register(&pdev->dev, &smdk_backlight_led);

在smdk_backlight_led结构体里,设置了节点名称lcd-backlight和控制接口等。

而led_classdev_register()是led-class里的函数。最终调用了device_createp 这样的函数实现创建节点。

 

原创粉丝点击