S3C6410 LCD 背光PWM控制研究

 

一般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;
}

发布了1 篇原创文章 · 获赞 1 · 访问量 4007
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览