강좌 & 팁
S5PV210 에서 PWM 으로 LCD 의 백라이트를 제어하는 드라아버를 만들 일이 생겨 간략히 만들어 보았습니다.
다른것들도 있긴 하지만 대부분 다른 파일들은 추가 돼 있다고 가정 하고, h/w 타이머와 클럭을 사용 해야 하므로
이 두가지 파일을 인크루드 해 주어야 합니다.
#include <plat/regs-timer.h>
#include <linux/clk.h>
--- 여기서 부터 주요 소스 --------------------------------------------------------
struct clk *pwm_clk;
static unsigned long brad_tcntb;
static unsigned long brad_tcmpb;
static unsigned long brad_tcnto;
//------------------------------------------------------------------------------
// pwm 클럭 초기화
//------------------------------------------------------------------------------
static void set_pwm_clk(void)
{
unsigned long brad_tcfg0;
unsigned long brad_tcfg1;
pwm_clk = clk_get(NULL, "timers");
clk_enable(pwm_clk);
brad_tcfg0 = readl(S3C2410_TCFG0);
brad_tcfg0 |= S3C2410_TCFG_PRESCALER0_MASK;
writel(brad_tcfg0, S3C2410_TCFG0);
brad_tcfg1 = readl(S3C2410_TCFG1);
brad_tcfg1 |= S3C2410_TCFG1_MUX_DIV16;
writel(brad_tcfg1, S3C2410_TCFG1);
printk("Bradkim PWM setting finish\n");
}
//------------------------------------------------------------------------------
// pwm 출력비 초기 값 100% 밝기
//------------------------------------------------------------------------------
static void default_pwm_duty(void)
{
brad_tcntb = readl(S3C2410_TCNTB(0));
brad_tcmpb = readl(S3C2410_TCMPB(0));
brad_tcnto = readl(S3C2410_TCNTO(0));
brad_tcntb = 101;
brad_tcmpb = 100;
writel(brad_tcntb, S3C2410_TCNTB(0));
writel(brad_tcmpb, S3C2410_TCMPB(0));
}
삼성 CPU 들은 비슷한 형태를 취하고 있어서 S3C2410 에서 만들어진 것들을 그대로 사용해서
S5PV210 에서도 레지스터를 같이 쓰고 있다는 것을 알 수 있습니다.
//------------------------------------------------------------------------------
// pwm 출력비 조절
//------------------------------------------------------------------------------
static void set_pwm_duty(unsigned int usr_tcmpb)
{
writel(usr_tcmpb, S3C2410_TCMPB(0));
// printk("bright : %d % \n",usr_tcmpb/100);
}
이제 ioctl 함수로 제어만 하면 되겠습니다.
//------------------------------------------------------------------------------
// 드라이버 ioctl
//------------------------------------------------------------------------------
static int bklight_ioctl( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg )
{
unsigned int bright;
switch(cmd)
{
//DO
case IOCTL_BKLIGHT_CONT :
if(copy_from_user( &bright, (void *)arg, sizeof(unsigned int) ))printk("copy_from_user error ! \n");
set_pwm_duty(bright );
return 0;
}
return -EINVAL;
}
--------------------------------------------------- 여기 까지 주요 소스 -----------------
pwm 에 대해 아는 사람은 알겠지만, 가장 간단 한 모드로 전체 펄스폭중 일정폭 동안 high, 나머지를 low 로 출력 하는
방식입니다.
이 폭 비율을 duty 비율이라 하고, 이 비율을 조절 함으로써 전류를 조절 하는 방법 입니다.
이 전류를 받아 lcd 의 백라이트의 밝기를 조절 하게 됩니다.
tcntb 는 전체 펄스의 폭이 되고 tcmpb 는 high 폭이 됩니다.
따라서 tcntb 가 101 이고 tcmpb 가 100 까지 이므로 정확히 말해 100 퍼센트 밝기는 안되는 셈이됩니다.
실험을 해보니 101 까지 가면 인터럽트가 발생되지 않아 hight 신호가 발생 되지 않는 문제가 있었습니다.
만약 전체 펄스 폭인 TCNTB 의 값을 너무 크게 (예를 들어 1000 ) 하면 시간이 너무 길어져 LCD 의 밝기가 조절 되기는
커녕 까박이는 것을 보게 될 것입니다.
물론 이 글에서는 실제 출력되는 GPIO 부분에 대한 설명이 없으나, GPIO 의 서정에 TOUT 모드가 있으며 GPD0_0 이 TIMER0 번의
PWM 출력을 내보내도록 설정되었습니다.
LCD 백라이트는 이 GPD0_0 으로 PWM 신호를 입력 받아 제어 하면 되겠습니다.
마지막으로 클럭을 초기화 에서 clk_enable(pwm_clk); 해주었기 때문에 디바이스를 close 할때 clk_disable(pwm_clk); 해주면 됩니다.