现在的位置: 首页 > 综合 > 正文

从应用层设置mx31-pdk板的lcd背光亮度

2013年04月07日 ⁄ 综合 ⁄ 共 16208字 ⁄ 字号 评论关闭
 

想在应用层自己可调整mx31-pdk板子lcd背光,以便用户能够进行lcd亮度的调整。

    该板子背光通过的电源控制芯片,飞思卡尔自己的13783进行控制,其开发包中已带了电源管理的驱动,包括背光控制的驱动,这里首先略微分析一下该背光驱动代码,然后搞明白应该如何来调节lcd背光亮度。

    首先要找到关于背光控制的驱动代码,经过寻找发现有关电压控制的驱动代码的存放路径为/drivers/mxc/pmic/mc13783/pmic_light.c,浏览该代码可以发现

一.关于驱动的注册的代码

pmic_light.c的最底部有以下代码:

static int __init pmic_light_init(void)

{

       pr_debug("PMIC
Light driver loading.../n");

       return
platform_driver_register(&pmic_light_driver_ldm);

}

static void __exit pmic_light_exit(void)

{

       platform_driver_unregister(&pmic_light_driver_ldm);

       pr_debug("PMIC
Light driver successfully unloaded/n");

}

subsys_initcall(pmic_light_init);

module_exit(pmic_light_exit);

MODULE_DESCRIPTION("PMIC_LIGHT");

从以上代码可看出这里进行了电源管理驱动pmic_light_driver_ldm的注册,而关于这个驱动的定义同样在该文件中,定义为:

static struct platform_driver
pmic_light_driver_ldm = {

       .driver
= {

                 .name = "pmic_light",

                 },

       .suspend
= pmic_light_suspend,

       .resume
= pmic_light_resume,

       .probe
= pmic_light_probe,

       .remove
= pmic_light_remove,

};

其中pmic_light_probe是该驱动注册时要调用的回调函数,这个函数很重要,在这个函数里可以进行设备device的保存,以及资源的获得,以及其他的。

二.Driver驱动pmic_light_probe回调函数阅读

    static
int pmic_light_probe(struct platform_device *pdev)

{

       int
ret = 0;

       struct
class_device *temp_class;

       while
(suspend_flag == 1) {

              swait++;

              /*
Block if the device is suspended */

              if
(wait_event_interruptible(suspendq, (suspend_flag == 0))) {

                     return
-ERESTARTSYS;

              }

       }

       pmic_light_major
= register_chrdev(0, "pmic_light", &pmic_light_fops);

       if
(pmic_light_major < 0) {

              printk(KERN_ERR
"Unable to get a major for pmic_light/n");

              return
pmic_light_major;

       }

       init_waitqueue_head(&suspendq);

       pmic_light_class
= class_create(THIS_MODULE, "pmic_light");

       if
(IS_ERR(pmic_light_class)) {

              printk(KERN_ERR
"Error creating pmic_light class./n");

              ret
= PTR_ERR(pmic_light_class);

              goto
err_out1;

       }

       temp_class
= class_device_create(pmic_light_class, NULL,

                                    MKDEV(pmic_light_major, 0),

                                    NULL, "pmic_light");

       if
(IS_ERR(temp_class)) {

              printk(KERN_ERR
"Error creating pmic_light class device./n");

              ret
= PTR_ERR(temp_class);

              goto
err_out2;

       }

       ret
= pmic_light_init_reg();

       if
(ret != PMIC_SUCCESS) {

              goto
err_out3;

       }

       printk(KERN_INFO
"PMIC Light successfully loaded/n");

       return
ret;

     
err_out3:

       class_device_destroy(pmic_light_class,
MKDEV(pmic_light_major, 0));

     
err_out2:

       class_destroy(pmic_light_class);

     
err_out1:

       unregister_chrdev(pmic_light_major,
"pmic_light");

       return
ret;

}

可以看出,register_chrdev(0,
"pmic_light", &pmic_light_fops)
注册了一个字符设备,名字为pmic_ligh,同时指定了它的fileoperations结构体为pmic_light_fops,关于该结构体定义同样子该c文件中,如下:

static struct file_operations pmic_light_fops = {

       .owner = THIS_MODULE,

       .ioctl =
pmic_light_ioctl,

       .open = pmic_light_open,

       .release =
pmic_light_release,

};

可以看出该设备驱动的用户层操作接口只有三个,还包括打开和关闭的两个必须函数,真正进行操作的函数只有pmic_light_ioctl一个函数。

三.设备驱动pmic_light_ioctl函数阅读

       static
int pmic_light_ioctl(struct inode *inode, struct file *file,

                         unsigned int cmd, unsigned long arg)

{

       t_bklit_setting_param
*bklit_setting = NULL;

       t_tcled_enable_param
*tcled_setting;

       t_fun_param
*fun_param;

       t_tcled_ind_param
*tcled_ind;

       if
(_IOC_TYPE(cmd) != 'p')

              return
-ENOTTY;

       switch
(cmd) {

       case
PMIC_BKLIT_TCLED_ENABLE:

              pmic_bklit_tcled_master_enable();

              break;

       case
PMIC_BKLIT_TCLED_DISABLE:

              pmic_bklit_tcled_master_disable();

              break;

       case
PMIC_BKLIT_ENABLE:

              pmic_bklit_master_enable();

              break;

       case
PMIC_BKLIT_DISABLE:

              pmic_bklit_master_disable();

              break;

       case
PMIC_SET_BKLIT:

              if
((bklit_setting = kmalloc(sizeof(t_bklit_setting_param),

                                        GFP_KERNEL)) == NULL) {

                     return
-ENOMEM;

              }

              if
(copy_from_user(bklit_setting, (t_bklit_setting_param *) arg,

                               sizeof(t_bklit_setting_param))) {

                     kfree(bklit_setting);

                     return
-EFAULT;

              }

              CHECK_ERROR_KFREE(pmic_bklit_set_mode(bklit_setting->channel,

                                                bklit_setting->mode),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_current(bklit_setting->channel,

                                                  bklit_setting->

                                                  current_level),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_dutycycle

                              (bklit_setting->channel,

                               bklit_setting->duty_cycle),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_cycle_time

                              (bklit_setting->cycle_time),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_boost_mode

                              (bklit_setting->en_dis),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_config_boost_mode

                              (bklit_setting->abms,
bklit_setting->abr),

                              (kfree(bklit_setting)));

              if
(bklit_setting->edge_slow != false) {

                     CHECK_ERROR_KFREE(pmic_bklit_enable_edge_slow(),

                                     (kfree(bklit_setting)));

              }
else {

                     CHECK_ERROR_KFREE(pmic_bklit_disable_edge_slow(),

                                     (kfree(bklit_setting)));

              }

              kfree(bklit_setting);

              break;

       case
PMIC_GET_BKLIT:

              if
((bklit_setting = kmalloc(sizeof(t_bklit_setting_param),

                                        GFP_KERNEL)) == NULL) {

                     return
-ENOMEM;

              }

              if
(copy_from_user(bklit_setting, (t_bklit_setting_param *) arg,

                               sizeof(t_bklit_setting_param))) {

                     kfree(bklit_setting);

                     return
-EFAULT;

              }

              CHECK_ERROR_KFREE(pmic_bklit_get_current(bklit_setting->channel,

                                                  &bklit_setting->

                                                  current_level),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_get_cycle_time

                              (&bklit_setting->cycle_time),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_get_dutycycle

                             
(bklit_setting->channel,

                               &bklit_setting->duty_cycle),

                              (kfree(bklit_setting)));

              bklit_setting->strobe
= BACKLIGHT_STROBE_NONE;

              CHECK_ERROR_KFREE(pmic_bklit_get_mode(bklit_setting->channel,

                                                &bklit_setting->mode),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_get_edge_slow

                              (&bklit_setting->edge_slow),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_get_boost_mode

                              (&bklit_setting->en_dis),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_gets_boost_mode

                              (&bklit_setting->abms,
&bklit_setting->abr),

                              (kfree(bklit_setting)));

              if
(copy_to_user((t_bklit_setting_param *) arg, bklit_setting,

                             sizeof(t_bklit_setting_param))) {

                     kfree(bklit_setting);

                     return
-EFAULT;

              }

              kfree(bklit_setting);

              break;

       case
PMIC_RAMPUP_BKLIT:

              CHECK_ERROR(pmic_bklit_rampup((t_bklit_channel)
arg));

              break;

       case
PMIC_RAMPDOWN_BKLIT:

              CHECK_ERROR(pmic_bklit_rampdown((t_bklit_channel)
arg));

              break;

       case
PMIC_OFF_RAMPUP_BKLIT:

              CHECK_ERROR(pmic_bklit_off_rampup((t_bklit_channel)
arg));

              break;

       case
PMIC_OFF_RAMPDOWN_BKLIT:

              CHECK_ERROR(pmic_bklit_off_rampdown((t_bklit_channel)
arg));

              break;

                     case
STROBE_SLOW:

                     CHECK_ERROR_KFREE(pmic_tcled_fun_strobe

                                     (fun_param->bank, fun_param->channel,

                                      TC_STROBE_SLOW), (kfree(fun_param)));

                     break;

              case
STROBE_FAST:

                     CHECK_ERROR_KFREE(pmic_tcled_fun_strobe

                                     (fun_param->bank,

                                      fun_param->channel, TC_STROBE_SLOW),

                                     (kfree(fun_param)));

                     break;

              case
CHASING_LIGHT_RGB_SLOW:

                     CHECK_ERROR_KFREE(pmic_tcled_fun_chasinglightspattern

                                     (fun_param->bank, PMIC_RGB, TC_SLOW),

                                     (kfree(fun_param)));

                     break;

       …………………..

………………….

       default:

              return
-EINVAL;

       }

       return
0;

}

这是标准的设备驱动函数,为了文章的完整性,这里重述一下上篇文章的关于ioctl的解释。用户的ioctl函数原型为int ioctl(int fd, ind cmd, …),适合对设备的一些特性进行控制,其中fd就是用户程序打开设备时使用open函数返回的文件描述符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。当需要这个参数时,把该参数的地址传递给static int pmic_battery_ioctl(struct inode *inode, struct file
*file, unsigned int cmd, unsigned long arg)
arg,以便进行数据的传入和回传(感觉是这样)。所以应用层只用调用标准的函数ioctl(int fd, ind cmd, …)并传递正确的cmd参数就可以了。这里就又有一个重要的事,就是分析以上代码,找出和背光有关的正确的cmd参数。

查看代码有两个case,查看后如下:

case
PMIC_BKLIT_ENABLE:

              pmic_bklit_master_enable();////return
PMIC_NOT_SUPPORTED;

              break;

       case
PMIC_BKLIT_DISABLE:

              pmic_bklit_master_disable();////return
PMIC_NOT_SUPPORTED;

              break;

以上俩个函数内容均为return
PMIC_NOT_SUPPORTED;
从函数内部的return可以看出这俩个命令无效,13783及驱动不支持以上两种操作。

 

关于背光的还有一个很重要的cmd,就是设置背光,如下:

       case
PMIC_SET_BKLIT:

              if
((bklit_setting = kmalloc(sizeof(t_bklit_setting_param),

                                        GFP_KERNEL)) == NULL) {

                     return
-ENOMEM;

              }

              if
(copy_from_user(bklit_setting, (t_bklit_setting_param *) arg,

                               sizeof(t_bklit_setting_param))) {

                     kfree(bklit_setting);

                     return
-EFAULT;

              }

     
//////
以上为读入参数值出现错误返回,若成功后依次执行下边的函数进行模式修改,

              CHECK_ERROR_KFREE(pmic_bklit_set_mode(bklit_setting->channel,

                                                bklit_setting->mode),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_current(bklit_setting->channel,

                                                  bklit_setting->current_level),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_dutycycle

                              (bklit_setting->channel,

                               bklit_setting->duty_cycle),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_cycle_time

                              (bklit_setting->cycle_time),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_set_boost_mode

                              (bklit_setting->en_dis),

                              (kfree(bklit_setting)));

              CHECK_ERROR_KFREE(pmic_bklit_config_boost_mode

                              (bklit_setting->abms,
bklit_setting->abr),

                              (kfree(bklit_setting)));

              if
(bklit_setting->edge_slow != false) {

                     CHECK_ERROR_KFREE(pmic_bklit_enable_edge_slow(),

                                     (kfree(bklit_setting)));

              }
else {

                     CHECK_ERROR_KFREE(pmic_bklit_disable_edge_slow(),

                                     (kfree(bklit_setting)));

              }

              kfree(bklit_setting);

              break;

后边的部分涉及到一个宏定义,在pmic_config.h中进行的定义,如下:

#define CHECK_ERROR_KFREE(func, freeptrs) /

do { /

  int
ret = (func); /

  if
(ret != PMIC_SUCCESS) /       
////////////
如果不成功

  { /

    
freeptrs; /                  
/////
执行free也就是kfree(bklit_setting);

    
return ret; /                
///////
并且直接返回.

  }/

} while(0);

可以看出该宏先执行func函数,成功则该宏完成,不成功则kfree(bklit_setting)并返回。可知一连串的CHECK_ERROR_KFREE宏定义实为依次执行各自的func,直到出现错误并立即返回。这里要求要提前把参数t_bklit_setting_param写好,然后通过命令写入寄存器.

关于t_bklit_setting_paramarch-mxc/pmic_light.h有这个定义,如下:

typedef struct {

       t_bklit_channel
channel; /*!< Channel */

       t_bklit_mode
mode;       /*!< Mode */

       t_bklit_strobe_mode
strobe;   /*!< Strobe mode */

       unsigned
char current_level;  /*!< Current level
*/

       unsigned
char duty_cycle;     /*!< Duty cycle */

       unsigned
char cycle_time;     /*!< Cycle time */

       bool
edge_slow;            /*!< Edge Slow */

       bool
en_dis;           /*!< Enable disable
boost mode */

       unsigned
int abms;  /*!< Adaptive boost

                             *   mode
selection */

       unsigned
int abr;     /*!< Adaptive

                             *  
boost reference */

} t_bklit_setting_param;

      

       case PMIC_SET_BKLIT:中调用了很多函数,比如pmic_bklit_set_mode,该文件中有定义:

PMIC_STATUS
pmic_bklit_set_mode(t_bklit_channel channel, t_bklit_mode mode)

{

       unsigned
int reg_value = 0;

       unsigned
int clear_val = 0;

       unsigned
int triode_val = 0;

       if
(suspend_flag == 1) {

              return
-EBUSY;

       }

       CHECK_ERROR(pmic_read_reg(LREG_0,
&reg_value, PMIC_ALL_BITS));

       switch
(channel) {

       case
BACKLIGHT_LED1:

              clear_val
= ~(MASK_TRIODE_MAIN_BL);

              triode_val
= MASK_TRIODE_MAIN_BL;

              break;

       case
BACKLIGHT_LED2:

              clear_val
= ~(MASK_TRIODE_MAIN_BL << INDEX_AUXILIARY);

              triode_val
= (MASK_TRIODE_MAIN_BL << INDEX_AUXILIARY);

              break;

       case
BACKLIGHT_LED3:

              clear_val
= ~(MASK_TRIODE_MAIN_BL << INDEX_KEYPAD);

              triode_val
= (MASK_TRIODE_MAIN_BL << INDEX_KEYPAD);

              break;

       default:

              return
PMIC_PARAMETER_ERROR;

       }

       reg_value
= (reg_value & clear_val);

       if
(mode == BACKLIGHT_TRIODE_MODE) {

              reg_value
= (reg_value | triode_val);

       }

       CHECK_ERROR(pmic_write_reg(LREG_0,
reg_value, PMIC_ALL_BITS));

       return
PMIC_SUCCESS;

}

分析上边这个函数可以知道t_bklit_channel channel这个参数很重要,直接决定了修改的寄存器的bit位置,t_bklit_channel包含在t_bklit_setting_param参数中,这个参数很重要,但是搜索后没有发现他的初始化内容。

这里很惶惑如何设置这些参数,但又发现可以把初始化好的参数读出来,然后修改后写回就可以了。如下case

case PMIC_GET_BKLIT:

    ……………………

很幸运,在上边的case中发现了可以读出设置的cmd,这样的话可以先读,修改后再写入。

 

 

以上方法虽然可行但并不是一个很好的办法,后来发现,
/////pmic_testapp_light.c
中的一个函数,

void enable_backlight(int fp,
t_bklit_setting_param * setting)

{

       setting->channel
= BACKLIGHT_LED1;

       setting->current_level
= 4;

       setting->duty_cycle
= 7;

       setting->mode
= BACKLIGHT_CURRENT_CTRL_MODE;

       setting->cycle_time
= 2;

       setting->strobe
= BACKLIGHT_STROBE_NONE;

       setting->edge_slow
= false;

       setting->en_dis
= 0;

       setting->abms
= 0;

       setting->abr
= 0;

       printf("Main
Backlight LED ON./n");

       ioctl(fp,
PMIC_SET_BKLIT, setting);

       sleep(1);

       setting->channel
= BACKLIGHT_LED2;

       printf("Auxiliary
Backlight LED ON./n");

       ioctl(fp,
PMIC_SET_BKLIT, setting);

       sleep(1);

       printf("Keypad
Backlight LED ON./n");

       setting->channel
= BACKLIGHT_LED3;

       ioctl(fp,
PMIC_SET_BKLIT, setting);

       /*
Check result */

       if(ask_user("Did
you see the BACKLIGHTS ON?") == TPASS)

              printf("Test
Passed/n");

       else

              printf("Test
Failed/n");

}

这样可以确定, setting->channel
= BACKLIGHT_LED1
对应Main
Backlight LED

setting->channel = BACKLIGHT_LED2对应Auxiliary Backlight LED

setting->channel = BACKLIGHT_LED3对应Keypad Backlight LED

lcd的背光应该是Main Backlight LED,这样就可以仿照上边的初始化确定设置了。

 

 

四.参数PMIC_SET_BKLIT等参数的定义

       通过查看代码,在 <asm/arch/pmic_light.h>中有如下定义:

#define PMIC_SET_BKLIT     
_IOW('p', 0xe2, int)

#define PMIC_GET_BKLIT      _IOWR('p', 0xe3, int)

………

而在/include/asm-generic/ioctl.h中有如下定义:

#define _IOC_NRBITS  8

#define _IOC_TYPEBITS     8

#define _IOC_SIZEBITS       14

#define _IOC_DIRBITS 2

 

#define _IOC_NRMASK       ((1 << _IOC_NRBITS)-1)

#define _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)

#define _IOC_SIZEMASK     ((1 << _IOC_SIZEBITS)-1)

#define _IOC_DIRMASK      ((1 << _IOC_DIRBITS)-1)

 

#define _IOC_NRSHIFT       0

#define _IOC_TYPESHIFT   (_IOC_NRSHIFT+_IOC_NRBITS)

#define _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)

#define _IOC_DIRSHIFT      (_IOC_SIZESHIFT+_IOC_SIZEBITS)

 

#define _IOC_NONE     0U

#define _

【上篇】
【下篇】

抱歉!评论已关闭.