Chinaunix首页 | 论坛 | 博客
  • 博客访问: 280015
  • 博文数量: 95
  • 博客积分: 2047
  • 博客等级: 大尉
  • 技术积分: 1022
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-14 16:18
文章分类

全部博文(95)

文章存档

2013年(1)

2011年(94)

我的朋友

分类: 嵌入式

2011-08-28 21:11:31

一般LCD的背光LED是通过PWM控制,调节PWM的占空比即可调整背光亮度。

比如S3C6410的GPF15,即PWM1,即可连接LCD的背光控制接口,进行背光控制。

其工作流程如下:

1)在linux中,通过控制sys目录参数修改背光,如:
/sys/devices/platform/s3c-lcd # echo 200 > backlight_level

2)该操作影响/driver/video/samsung/s3cfb.c中函数

static int s3cfb_sysfs_store_backlight_level(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
{
unsigned long value = simple_strtoul(buf, NULL, 10);

if (value < s3cfb_fimd.backlight_min || value > s3cfb_fimd.backlight_max)
return -ERANGE;

s3cfb_set_backlight_level(value);

return len;
}

3)s3cfb_set_backlight_level(value);同样位于/driver/video/samsung/s3cfb.c
static void s3cfb_set_backlight_level(int to)
{
s3cfb_fimd.backlight_level = to;

if (s3cfb_fimd.set_brightness)
(s3cfb_fimd.set_brightness)(to);
}

4)s3cfb_fimd.set_brightness是具体LCD对应参数的函数指针
一般位于/driver/video/samsung/your lcd.c (eg.s3cfb_lte480wv.c)
检查初始化LCD时是否有添加该参数,红色标注:
s3cfb_fimd.set_lcd_power = lcd_power_ctrl;
s3cfb_fimd.set_backlight_power = backlight_power_ctrl;
s3cfb_fimd.set_brightness = backlight_level_ctrl;

s3cfb_fimd.backlight_min = BACKLIGHT_LEVEL_MIN;
s3cfb_fimd.backlight_max = BACKLIGHT_LEVEL_MAX;

ok,上面的只是函数指针,接着在同文件中需要实现该函数:
void backlight_level_ctrl(s32 value)
{
if ((value < BACKLIGHT_LEVEL_MIN) || /* Invalid Value */
(value > BACKLIGHT_LEVEL_MAX) ||
(value == backlight_level)) /* Same Value */
return;

s3cfb_set_brightness((int)(value/3));

backlight_level = value;
}

5)s3cfb_set_brightness让我们又跳到了drivers/video/samsung/s3cfb_fimd4x.c中
注意这段需要PWM支持
void s3cfb_set_brightness(int val)
{
int channel = 1; /* must use channel-1 */
int usec = 0; /* don't care value */
unsigned long tcnt = 1000;
unsigned long tcmp = 0;

if (val < 0)
val = 0;

if (val > S3CFB_MAX_BRIGHTNESS)
val = S3CFB_MAX_BRIGHTNESS;

s3cfb_fimd.brightness = val;
tcmp = val * 5;

s3c6410_timer_setup (channel, usec, tcnt, tcmp);
}

6)channel1 即为PWM1,s3c6410_timer_setup函数位于arch/arm/plat-s3c64xx/pwm-s3c6410.c
tcnt 是PWM的周期
tcmp 是PWM的占空比
一下代码是PWM配置过程,精简过的代码便于阅读。
int s3c6410_timer_setup (int channel, int usec, unsigned long g_tcnt, unsigned long g_tcmp)
{

tcnt = 0xffffffff;  /* default value for tcnt */
/* read the current timer configuration bits */
tcon = __raw_readl(S3C_TCON);
tcfg1 = __raw_readl(S3C_TCFG1);
tcfg0 = __raw_readl(S3C_TCFG0);
clk = clk_get(NULL, "timers");
if (IS_ERR(clk))
panic("failed to get clock for pwm timer");
clk_enable(clk);
pclk = clk_get_rate(clk);
/* configure clock tick */
switch(channel)
{
case 1:
/* set gpio as PWM TIMER1 to signal output*/
s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C64XX_GPF15_PWM_TOUT1);
s3c_gpio_setpull(S3C64XX_GPF(15), S3C_GPIO_PULL_NONE);
tcfg1 &= ~S3C_TCFG1_MUX1_MASK;
tcfg1 |= S3C_TCFG1_MUX1_DIV2;
tcfg0 &= ~S3C_TCFG_PRESCALER0_MASK;
tcfg0 |= (PRESCALER) << S3C_TCFG_PRESCALER0_SHIFT;
tcon &= ~(7<<8);
tcon |= S3C_TCON_T1RELOAD;
break;

}
__raw_writel(tcfg1, S3C_TCFG1);
__raw_writel(tcfg0, S3C_TCFG0);
__raw_writel(tcon, S3C_TCON);
tcnt = 160;
__raw_writel(tcnt, S3C_TCNTB(channel));
tcmp = 110;
__raw_writel(tcmp, S3C_TCMPB(channel));
switch(channel)
{
case 1:
tcon |= S3C_TCON_T1MANUALUPD;
break;

}
__raw_writel(tcon, S3C_TCON);
tcnt = g_tcnt;
__raw_writel(tcnt, S3C_TCNTB(channel));
tcmp = g_tcmp;
__raw_writel(tcmp, S3C_TCMPB(channel));
/* start the timer running */
s3c6410_pwm_start ( channel);
return 0;
}

阅读(1101) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~