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); 해주면 됩니다.