LCD(五)Backlight背光子系统

一、Backlight背光子系统概述

LCD的背光原理主要是由核心板的一根引脚控制背光电源,一根PWM引脚控制背光亮度组成,应用程序可以通过改变PWM的频率达到改变背光亮度的目的。

二、PWM核心驱动

代码/arch/arm/plat-samsung/pwm.c

内核中需要使能“PWM device support”

System Type -->
    [*]PWM device support
它是 pwm核心驱动,该驱动把设备和驱动没有分离开来,都写在了这个 pwm.c中,我们先看看 pwm.c中的驱动部分
static int __init pwm_init(void)
{
	int ret;

	clk_scaler[0] = clk_get(NULL, "pwm-scaler0");//获取0号时钟
	clk_scaler[1] = clk_get(NULL, "pwm-scaler1");//获取1号时钟

	if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) {
		printk(KERN_ERR "%s: failed to get scaler clocks\n", __func__);
		return -EINVAL;
	}

	ret = platform_driver_register(&s3c_pwm_driver);//注册pwm驱动
	if (ret)
		printk(KERN_ERR "%s: failed to add pwm driver\n", __func__);

	return ret;
}
//s3c_pwm_driver定义
static struct platform_driver s3c_pwm_driver = {
	.driver		= {
		.name	= "s3c24xx-pwm",//驱动名
		.owner	= THIS_MODULE,
	},
	.probe		= s3c_pwm_probe,//探测函数
	.remove		= __devexit_p(s3c_pwm_remove),
	.suspend	= s3c_pwm_suspend,
	.resume		= s3c_pwm_resume,
};

三、Backlight核心驱动

代码/driver/video/backlight/backlight.c

内核中需要使能“Lowlevel Backlight controls”

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

代码分析

static int __init backlight_class_init(void)
{
	backlight_class = class_create(THIS_MODULE, "backlight");//在/sys/class下注册backlight类
	if (IS_ERR(backlight_class)) {
		printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
				PTR_ERR(backlight_class));
		return PTR_ERR(backlight_class);
	}

	backlight_class->dev_attrs = bl_device_attributes;//添加类属性
	backlight_class->suspend = backlight_suspend;
	backlight_class->resume = backlight_resume;
	return 0;
}

backlight背光系统的主要就是靠这个类属性,设置背光值就是向这个类属性中某个成员写入背光值,这个类属性就是给用户的同一接口

#define __ATTR(_name,_mode,_show,_store) { \
	.attr = {.name = __stringify(_name), .mode = _mode },	\
	.show	= _show,					\
	.store	= _store,					\
}
static struct device_attribute bl_device_attributes[] = {
	__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
	__ATTR(brightness, 0644, backlight_show_brightness,
		     backlight_store_brightness),
	__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
		     NULL),
	__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
	__ATTR(type, 0444, backlight_show_type, NULL),
	__ATTR_NULL,
};
很明显,在backlight类中我们创建了bl_power,brightness,actural_brightness,max_brightness四个成员,其中brightness是当前亮度,max_brightness是最大亮度。当用户层通过cat或者echo命令就会触发这些成员。对于这些属性的读写函数,我们先看看读的函数backlight_show_max_brightness吧
static ssize_t backlight_show_max_brightness(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct backlight_device *bd = to_backlight_device(dev);

	return sprintf(buf, "%d\n", bd->props.max_brightness);//输出最大亮度
}

这个函数很简单,但是重点是引入了几个backlight背光子系统的几个重要的数据结构,我们好好学习下。

首先是backlight背光子系统的设备结构体backlight_device

struct backlight_device {
	/* Backlight properties */
	struct backlight_properties props;//背光属性

	/* Serialise access to update_status method */
	struct mutex update_lock;

	/* This protects the 'ops' field. If 'ops' is NULL, the driver that
	   registered this device has been unloaded, and if class_get_devdata()
	   points to something in the body of that driver, it is also invalid. */
	struct mutex ops_lock;
	const struct backlight_ops *ops;//背光操作函数,类似于file_operation

	/* The framebuffer notifier block */
	struct notifier_block fb_notif;

	struct device dev;//内嵌设备
};
下面先看看背光属性结构体backlight_properties
struct backlight_properties {
	/* Current User requested brightness (0 - max_brightness) */
	int brightness;//当前背光值
	/* Maximal value for brightness (read-only) */
	int max_brightness;//最大背光值
	/* Current FB Power mode (0: full on, 1..3: power saving
	   modes; 4: full off), see FB_BLANK_XXX */
	int power;
	/* FB Blanking active? (values as for power) */
	/* Due to be removed, please use (state & BL_CORE_FBBLANK) */
	int fb_blank;
	/* Backlight type */
	enum backlight_type type;
	/* Flags used to signal drivers of state changes */
	/* Upper 4 bits are reserved for driver internal use */
	unsigned int state;

#define BL_CORE_SUSPENDED	(1 << 0)	/* backlight is suspended */
#define BL_CORE_FBBLANK		(1 << 1)	/* backlight is under an fb blank event */
#define BL_CORE_DRIVER4		(1 << 28)	/* reserved for driver specific use */
#define BL_CORE_DRIVER3		(1 << 29)	/* reserved for driver specific use */
#define BL_CORE_DRIVER2		(1 << 30)	/* reserved for driver specific use */
#define BL_CORE_DRIVER1		(1 << 31)	/* reserved for driver specific use */

};

在看看背光操作函数

struct backlight_ops {
	unsigned int options;

#define BL_CORE_SUSPENDRESUME	(1 << 0)

	/* Notify the backlight driver some property has changed */
	int (*update_status)(struct backlight_device *);//更新背光状态
	/* Return the current backlight brightness (accounting for power,
	   fb_blank etc.) */
	int (*get_brightness)(struct backlight_device *);//获取背光值
	/* Check if given framebuffer device is the one bound to this backlight;
	   return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */
	int (*check_fb)(struct backlight_device *, struct fb_info *);
};
当前背光值函数 backlight_store_brightness
static ssize_t backlight_store_brightness(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int rc;
	struct backlight_device *bd = to_backlight_device(dev);
	unsigned long brightness;

	rc = strict_strtoul(buf, 0, &brightness);
	if (rc)
		return rc;

	rc = -ENXIO;

	mutex_lock(&bd->ops_lock);
	if (bd->ops) {
		if (brightness > bd->props.max_brightness)
			rc = -EINVAL;
		else {
			pr_debug("backlight: set brightness to %lu\n",
				 brightness);
			bd->props.brightness = brightness;//传入背光值
			backlight_update_status(bd);//更新背光状态
			rc = count;
		}
	}
	mutex_unlock(&bd->ops_lock);

	backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);

	return rc;
}
static inline void backlight_update_status(struct backlight_device *bd)
{
	mutex_lock(&bd->update_lock);
	if (bd->ops && bd->ops->update_status)
		bd->ops->update_status(bd);
	mutex_unlock(&bd->update_lock);
}
对于这个backlight背光核心层驱动backlight.c,剩下的就是这个pwm.c给我们提供了哪些接口函数了
struct backlight_device *backlight_device_register(const char *name,
              struct device *parent, void *devdata, struct backlight_ops *ops)

void backlight_device_unregister(struct backlight_device *bd)

EXPORT_SYMBOL(backlight_device_register);  //注册背光设备
EXPORT_SYMBOL(backlight_device_unregister); //注销背光设备

四、基于PWM&Backlight的蜂鸣器驱动

        结合上面的 PWM核心层和 Backlight背光子系统核心层,根据基于 pwm的背光驱动 /driver/video/backlight/pwm_bl.c来修改成基于 tq210的蜂鸣器驱动

内核中需要使能“Generic PWM based Backlight Driver”

Device Drivers --->
    Graphics support  --->
        [*] Backlight & LCD device support  --->
            <*>  Generic PWM based Backlight Driver

tq210蜂鸣器使用GPD0_1口,该端口工作在TOU0模式下,就可以通过设备定时器的TCNT和TCMP来控制定时器的波形。

首先,在tq210的BSP文件mach-tq210.c,如下添加

static struct platform_device tq210_backlight_device = {
	.name		= "pwm-backlight",//设备名
	.dev		= {
		.parent		= &s3c_device_timer[0].dev,//该设备基于pwm中的0号定时器
		.platform_data	= &tq_backlight_data,
	},
};

添加平台数据

static struct platform_pwm_backlight_data tq210_backlight_data = {
	.pwm_id		= 0,//对应的就是Timer0
	.max_brightness	= 255,//最大亮度
	.dft_brightness	= 100,//255,//当前亮度
        .lth_brightness = 50,//咱不知道干啥用的 
        .pwm_period_ns	= 20000,//78770,//T0,即输出时钟周期
	.init		= tq210_backlight_init,//端口初始化
	.exit		= tq210_backlight_exit,
};
static int tq210_backlight_init(struct device *dev)
{
	int ret;

	ret = gpio_request(S5PV210_GPD0(0), "Backlight");
	if (ret) {
		printk(KERN_ERR "failed to request GPD for PWM-OUT 0\n");
		return ret;
	}

	/* Configure GPIO pin with S5PV210_GPD_0_0_TOUT_0 */
	s3c_gpio_cfgpin(S5PV210_GPD0(0), S3C_GPIO_SFN(2));

	return 0;
}

static void tq210_backlight_exit(struct device *dev)
{
	s3c_gpio_cfgpin(S5PV210_GPD0(0), S3C_GPIO_OUTPUT);
	gpio_free(S5PV210_GPD0(0));
}

然后把tq210_backlight_device添加到tq210_devices数组

static struct platform_device *tq210_devices[] __initdata = {
	...
	
#ifdef CONFIG_BACKLIGHT_PWM
	&s3c_device_timer[0],
	&s3c_device_timer[1],
	&s3c_device_timer[2],
	&s3c_device_timer[3],
	&tq210_backlight_device,//同时添加对应的s3c_device_timer[0]
#endif

	...
};

最后添加头文件

#include <linux/pwm_backlight.h>







猜你喜欢

转载自blog.csdn.net/JerryGou/article/details/80219479
今日推荐