echo timer > /sys/class/leds/*/trigger

来源:互联网 发布:阿里企业邮箱绑定域名 编辑:程序博客网 时间:2024/06/06 00:13

最简单的Application Framework之灯光系统解析

1<. 灯光三个属性:

1<. brightness : 0 ~ 255 
2<. color : RGB 
3<. blink : onMs, offMs

[定时器]:    Linux LED Class : Linux已经对灯光系统的大部分功能都封装好了函数。    <路径>: Linux x.xx.x/drivers/leds

2<. 解析led-class.c

 1<. 情景分析   leds_init     class_create : 创建一个class,特殊的地方在于他有以下的设备属性static struct device_attribute led_class_attrs[] = {    __ATTR(brightness, 0666, led_brightness_show, led_brightness_store),    __ATTR(max_brightness, 0444, led_max_brightness_show, NULL),#ifdef CONFIG_LEDS_TRIGGERS    __ATTR(trigger, 0666, led_trigger_show, led_trigger_store),#endif    __ATTR_NULL,}; 2<. 使用:eg   echo 255 > /sys/class/leds/led1/brightness : 就会导致 led_brightness_store()被调用   cat /sys/class/leds/led1/brightness : 最终会导致 led_brightness_show() 被调用   cat /sys/class/leds/led1/max_brightness : 最终会导致 led_max_brightness_show() 被调用 3<. 关于闪烁的情景分析    1<. trigger目录      echo timer > /sys/class/leds/led1/trigger :最终会导致 led_trigger_store()           led_trigger_store(struct device *dev, struct device_attribute *attr,            const char *buf, size_t count)               /* 1. 首先会把 trigger_name 从 buf 里面取出来 : 就是timer */               strncpy(trigger_name, buf, sizeof(trigger_name) - 1);               /* 2. 从trigger_list找出名为 "timer" 的 trigger */               list_for_each_entry(trig, &trigger_list, next_trig) {                   if (!strcmp(trigger_name, trig->name)) {                       /* 3. 调用*/                       led_trigger_set(led_cdev, trig);                           /* 4. 把 trigger 放入 led_classdev 的 trig_list中 */                           list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);                           led_cdev->trigger = trigger;                           /* 5.  */                           trigger->activate(led_cdev);                               /* 6. 对于 "Timer" */                               timer_trig_activate()                                   /* 7. 创建2个文件 :delay_off, delay_on */                                     device_create_file(led_cdev->dev, &dev_attr_delay_on);                                   device_create_file(led_cdev->dev, &dev_attr_delay_off);                                   /* 8. 让LED闪烁, 初始化 */                                   led_blink_set()                                       if (!*delay_on && !*delay_off){                                            *delay_on = *delay_off = 500;                                       }                                   led_set_software_blink(led_cdev, *delay_on, *delay_off);                                      led_set_brightness(led_cdev, led_cdev->blink_brightness);                                      /* 调用软件定时器来实现 */                                      mod_timer(&led_cdev->blink_timer, jiffies + 1);                                      /* [补充]. 在/sys/目录下的文件都对应了读/写函数 */                   }               }
/* 当我们访问 delay_off, delay_on 文件时:就会导致led_delay_ox_show(), led_delay_ox_store() 被调用*/static DEVICE_ATTR(delay_on, 0666, led_delay_on_show, led_delay_on_store);static DEVICE_ATTR(delay_off, 0666, led_delay_off_show, led_delay_off_store);
  • 1
  • 2
  • 3
      2<. delay_on文件          echo 1000 > /sys/class/leds/led1/trigger/delay_on;           led_delay_on_store()             led_blink_set();   // 让LED闪烁            led_cdev->blink_delay_on = state;  

3<. 怎么写驱动

1<. 分配led_classdev

2<. 设置 :暂时需要设置的参数

1<. led_cdev->max_brightness //最大的亮度 
2<. led_cdev->flags //当前状态 
3<. led_cdev->brightness //当前亮度 
4<. led_cdev->name //创建设备是所用的名字 
5<. led_cdev->default_trigger //默认的闪烁方式 
6<. led_cdev->brightness_set(); //当应用程序访问灯光时调用的函数

3<. 注册:led_classdev_register


4<. 开始狗血的写起代码 : 参考leds-s3c24xx.c

1<. 修改之前的leds_4412.c 
2<. 上传

linux x.xx.x/drivers/leds

3<. 修改内核Makefile

vim linux x.xx.x/drivers/leds/Makefile

4<. 添加配置项 :

CONFIG_LEDS_CLASS 
CONFIG_LEDS_TRIGGERS 
CONFIG_LEDS_TRIGGER_TIMER

Location: 
-> Device Drivers 
-> LED Support (NEW_LEDS [=y]) 
[*] LED Class Support 
[*] LED Trigger Support 
<*> LED Timer Support

5<. 编译 && 烧写

 [补充]:     ledtrig-timer.c : 定时器的功能由他提供

5<. 调试

1<. 查看class目录下面是否存在4个led           ls /sys/class/leds              ![content](http://img.blog.csdn.net/20170807223144261?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0NDM5ODk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)2<. 控制    点亮:        echo 255 > /sys/class/leds/led1/brightness    闪烁:        1<. 每500ms亮灭一次            echo timer > /sys/class/leds/led1/trigger                [补充]:同时会发现目录下多了好几个文件             ![echo 前](http://img.blog.csdn.net/20170807223111237?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0NDM5ODk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)            ![echo 后](http://img.blog.csdn.net/20170807223133288?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0NDM5ODk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)        2<. 每1000ms亮,2000ms灭            echo 1000 > /sys/class/leds/led1/trigger/delay_on; 

echo 2000 > /sys/class/leds/led1/trigger/delay_off;

平台:mt6582 + android 4.4

hal层(mediatek/hardware/liblights/lights.c):

如果要点亮一个led灯,例如充电的指示灯(red led),sysfs节点是"/sys/class/leds/red/brightness",我们可以通过echo 255 > /sys/class/leds/red/brightness的方式打开这个led灯,通过echo 0 > /sys/class/leds/red/brightness来关闭这个led灯,那么hal层是如何做的呢?操作red led灯的函数为blink_red,代码如下:

[cpp] view plain copy
  1. static int  
  2. blink_red(int level, int onMS, int offMS)  
  3. {  
  4.     static int preStatus = 0; // 0: off, 1: blink, 2: no blink  
  5.     int nowStatus;  
  6.     int i = 0;  
  7.   
  8.     if (level == 0)  
  9.         nowStatus = 0;  
  10.     else if (onMS && offMS)  
  11.         nowStatus = 1;  
  12.     else  
  13.         nowStatus = 2;  
  14.   
  15.     if (preStatus == nowStatus)  
  16.         return -1;  
  17.   
  18. #ifdef LIGHTS_DBG_ON  
  19.     ALOGD("blink_red, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);  
  20. #endif  
  21.     if (nowStatus == 0) {  
  22.             write_int(RED_LED_FILE, 0);  
  23.     }  
  24.     else if (nowStatus == 1) {  
  25. //          write_int(RED_LED_FILE, level); // default full brightness  
  26.         write_str(RED_TRIGGER_FILE, "timer");  
  27.         while (((access(RED_DELAY_OFF_FILE, F_OK) == -1) || (access(RED_DELAY_OFF_FILE, R_OK|W_OK) == -1)) && i<10) {  
  28.             ALOGD("RED_DELAY_OFF_FILE doesn't exist or cannot write!!\n");  
  29.             led_wait_delay(5);//sleep 5ms for wait kernel LED class create led delay_off/delay_on node of fs  
  30.             i++;  
  31.         }  
  32.         write_int(RED_DELAY_OFF_FILE, offMS);  
  33.         write_int(RED_DELAY_ON_FILE, onMS);  
  34.     }  
  35.     else {  
  36.         write_str(RED_TRIGGER_FILE, "none");  
  37.             write_int(RED_LED_FILE, 255); // default full brightness  
  38.     }  
  39.   
  40.     preStatus = nowStatus;  
  41.   
  42.     return 0;  
  43. }  
这个函数带有三个参数,其中level表示灯亮度的级别,对于led就两个状态,0和255,表示灯灭和灯亮这两种情况,而onMS和offMS这两个参数对应闪烁这种情况,表示灯亮的时间和灯灭的时间,从名字上来看,单位应该是毫秒级。
preStatus和nowStatus两个变量表示led灯之前的状态和现在的状态,所以preStatus加了个static关键字。如果是0表示关闭led灯,如果是1,表示有闪烁,如果是2,表示打开led灯。
既然nowStatus有三个状态,那么这里就要根据传递进来的三个参数做判断了,如果level为0,那就是关闭led灯这个状态,如果如果level不为0,那么又有两个状态,即onMS和offMS都不为0,就是闪烁这个状态,如果为0就是常亮这个状态。
如果nowStatus同preStatus值相同,直接返回,因为同之前状态相同吗,没有什么好修改的。
如果不相同,那么肯定要根据这三个状态来做处理了。首先是0这个状态,直接调用write_int函数去关闭led灯,代码如下:
[cpp] view plain copy
  1. static int  
  2. write_int(char const* path, int value)  
  3. {  
  4.     int fd;  
  5.   
  6. #ifdef LIGHTS_INFO_ON  
  7.     ALOGD("write %d to %s", value, path);  
  8. #endif  
  9.   
  10.     fd = open(path, O_RDWR);  
  11.     ALOGD("write_int open fd=%d\n", fd);  
  12.     if (fd >= 0) {  
  13.         char buffer[20];  
  14.         int bytes = sprintf(buffer, "%d\n", value);  
  15.         int amt = write(fd, buffer, bytes);  
  16.         close(fd);  
  17.         return amt == -1 ? -errno : 0;  
  18.     } else {  
  19.         return -errno;  
  20.     }  
  21. }  
我们看这就是一个典型的文件操作函数,有打开、有关闭,有写文件操作灯,对应上面的。所以说write_int(RED_LED_FILE, 0);这句就对应echo 0 > /sys/class/leds/red/brightness。

如果是1这种情况,首先向"/sys/class/leds/red/trigger"这个文件写入了"timer"这个字符串信息,从写入字符串这个信息来看应该只是起到一个显示作用,表示此时led灯处于一个什么状态。然后判断"/sys/class/leds/red/delay_off"这文件是否具有可读可以操作。为什么这里不判断"/sys/class/leds/red/delay_on"也是否具有可读可写操作呢,而只单单判断delay_off这个文件呢,暂时还明白作者的意图。
如果具有可读可写操作权限,那么向dealy_off这个文件写入offMS值,向delay_on这个文件写入onMS值,表示熄灭和点亮的时间值。

如果是2这种情况,就直接调用write_int函数往brightness这个文件写入255这个值,点亮led灯,最后保存此时led的状态。

从上面可以看出,在上层点亮一个led灯是很简单的,由于充电指示灯有可能有三个,分别是红、绿、蓝,所以这里还提供了blink_green、blink_blue这两个函数,由于操作方法都是完全相同的,所以这里也不再描述了。

在mtk代码中除了充电led指示灯之外,还包括按键灯、lcd背光灯等等。

按键灯这里提供了两个属性文件"/sys/class/leds/keyboard-backlight/brightness"和"/sys/class/leds/button-backlight/brightness",具体使用哪个要看底层是怎么配置的,如果在配置按键灯时使用的是"keyboard-backlight"这个名字,那操作时就使用前面那个属性文件,如果使用的是"button-backlight"这个名字,那就是用后面那个属性文件。通过代码来看操作这两个属性的文件代码完全一样,所以说应该是通用的,按键灯只有两个状态,即点亮和熄灭这两个状态,对应brightness值就是255和0。

而lcd背光灯的属性文件为"/sys/class/leds/lcd-backlight/brightness",可以往这个文件写入合适的亮度值来调节lcd的背光亮度,这部分代码如下:
[cpp] view plain copy
  1. static int  
  2. set_light_backlight(struct light_device_t* dev,  
  3.         struct light_state_t const* state)  
  4. {  
  5.     int err = 0;  
  6.     int brightness = rgb_to_brightness(state);  
  7.     pthread_mutex_lock(&g_lock);  
  8.     g_backlight = brightness;  
  9.     err = write_int(LCD_FILE, brightness);  
  10.     if (g_haveTrackballLight) {  
  11.         handle_trackball_light_locked(dev);  
  12.     }  
  13.     pthread_mutex_unlock(&g_lock);  
  14.     return err;  
  15. }  
首先调用reg_to_brightness函数将rgb表示的一个值转换成一个亮度值,而这个亮度值的范围是0~255,最后将这个值写入到brightness这个文件中,注意这里的brightness值不在只有0或255这两个取值了,而是0~255这样一个范围,值越大越亮,而0即关闭lcd背光。


hal层看完了,我们再来看kernel层,kernel模块初始化代码在mediatek/kernel/drivers/leds/leds_drv.c中。首先是模块初始化和卸载函数(注:省略了部分代码,只提取出了主干代码):
[cpp] view plain copy
  1. static struct platform_driver mt65xx_leds_driver = {  
  2.     .driver     = {  
  3.         .name   = "leds-mt65xx",  
  4.         .owner  = THIS_MODULE,  
  5.     },  
  6.     .probe      = mt65xx_leds_probe,  
  7.     .remove     = mt65xx_leds_remove,  
  8.     .shutdown   = mt65xx_leds_shutdown,  
  9. };  
  10.   
  11. static int __init mt65xx_leds_init(void)  
  12. {  
  13.     platform_driver_register(&mt65xx_leds_driver);  
  14. }  
  15.   
  16. static void __exit mt65xx_leds_exit(void)  
  17. {  
  18.     platform_driver_unregister(&mt65xx_leds_driver);  
  19. }  
而平台设备定义在mediatek/platform/mt6582/kernel/core/mt_devs.c中:
[cpp] view plain copy
  1. static struct platform_device mt65xx_leds_device = {  
  2.     .name   = "leds-mt65xx",  
  3.     .id     = -1  
  4. };  
再来看probe函数:
[cpp] view plain copy
  1. static int __init mt65xx_leds_probe(struct platform_device *pdev)  
  2. {  
  3.     struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();  
  4.       
  5.     get_div_array();  
  6.       
  7.     for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {  
  8.         if (cust_led_list[i].mode == MT65XX_LED_MODE_NONE) {  
  9.             g_leds_data[i] = NULL;  
  10.             continue;  
  11.         }  
  12.           
  13.         g_leds_data[i] = kzalloc(sizeof(strcut mt65xx_led_data), GFP_KERNEL);  
  14.         if (!g_leds_data[i]) {  
  15.             ret = -EN0MEM;  
  16.             goto err;  
  17.         }  
  18.           
  19.         g_leds_data[i]->cust.mode = cust_led_list[i].mode;  
  20.         g_leds_data[i]->cust.data = cust_led_list[i].data;  
  21.         g_leds_data[i]->cust.name = cust_led_list[i].name;  
  22.           
  23.         g_leds_data[i]->cdev.name = cust_led_list[i].name;  
  24.         g_leds_data[i]->cust.config_data = cust_led_list[i].config_data;  
  25.           
  26.         g_leds_data[i]->cdev.brightness_set = mt65xx_led_set;  
  27.         g_leds_data[i]->cdev.blink_set = mt65xx_blink_set;  
  28.           
  29.         INIT_WORK(&g_leds_data[i]->work, mt_mt65xx_led_work);  
  30.           
  31.         led_classdev_register(&pdev->dev, &g_leds_data[i]->cdev);  
  32.     }  
  33. }  
首先调用mt_get_cust_led_list函数,改函数定义在mediatek/platform/mt6582/kernel/drivers/leds/leds.c中:
[cpp] view plain copy
  1. struct cust_mt65xx_led *mt_get_cust_led_list(void)  
  2. {  
  3.     return get_cust_led_list();  
  4. }  
而get_cust_led_list函数是和客户定制相关的,也就是作为一个普通的mtk开发者的话,你需要提供这么一个函数,在mediatek/custom/hexing82_cwet_kk/kernel/leds/mt65xx/cust_leds.c中提供了这么一个示例:
[cpp] view plain copy
  1. static struct cust_mt65xx_led cust_led_list[MT65XX_LED_TYPE_TOTAL] = {  
  2.     {"red",                 MT65XX_LED_MODE_PMIC, MT65XX_LED_PMIC_NLED_ISINK1, {0}},  
  3.     {"green",               MT65XX_LED_MODE_NONE, -1, {0}},  
  4.     {"blue",                MT65XX_LED_MODE_NONE, -1, {0}},  
  5.     {"jogball-backlight",   MT65XX_LED_MODE_NONE, -1, {0}},  
  6.     {"keyboard-backlight",  MT65XX_LED_MODE_NONE, -1, {0}},  
  7.     {"button-backlight",    MT65XX_LED_MODE_NONE, -1, {0}},  
  8.     {"lcd-backlight",       MT65XX_LED_MODE_CUST_BLS_PWM, int(disp_bls_set_backlight), {0}},  
  9. };  
  10.   
  11. struct cust_mt65xx_led *get_cust_led_list(void)  
  12. {  
  13.     return cust_led_list;  
  14. }  
即该函数需要返回一个全局的一个数组,那么led部分客户实际上需要做修改的地方也就只有这里,后面再来看客户应该怎么去做修改。

现在我们知道需要返回cust_mt65xx_led类型的一个数组。然后是get_div_array,这个函数主要是干什么的呢,这个函数主要是将leds.c中定义的div_array_hal数组复制给led_drv.c中定义的div_array,而div_array_hal数组是同pwm相关的,是pwm的分频参数,有1、2、4、8等等。

在for循环中,如果cust_led_list中定义的mode为MT65XX_LED_MODE_NONE,则直接跳过,不做任何处理。如果不为NONE,则按照标准的led程序来,其中brightness_set成员赋值为mt65xx_led_set,blink_set成员赋值为mt65xx_blink_set,最后调用led_classdev_register去注册。

ok,我们知道brightness_set就是用于来设置led灯的,所以我们首先来看mt65xx_led_set这个函数。
[cpp] view plain copy
  1. static void mt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level)  
  2. {  
  3.     struct mt65xx_led_data *led_data =  
  4.             container_of(led_cdev, struct mt65xx_led_data, cdev);  
  5.       
  6.     if (strcmp(led_data->cust.name, "lcd_backlight") == 0) {  
  7. #ifdef CONTROL_BL_TEMPERATURE  
  8.         mutex_lock(&bl_level_limit_mutex);  
  9.         current_level = level;  
  10.           
  11.         if (0 == limit_flag) {  
  12.             last_level = level;  
  13.         } else {  
  14.             if (limit < current_level) {  
  15.                 level = limit;  
  16.             }  
  17.         }  
  18.         mutex_unlock(&bl_level_limit_mutex);  
  19. #endif  
  20.     }  
  21.       
  22.     mt_mt65xx_led_set(led_cdev, level);  
  23. }  
在这个函数中,首先判断是否是lcd背光,如果是背光,则对level有加限制,如果level超过limit这个值,那么将level值设置成为limit值,limit值初始化为255,即level值最大只能为255。而level是设置led背光级别的,对于lcd背光来说,范围是0~255。最后调用mt_mt65xx_led_set函数。

mt_mt65xx_led_set函数在led.c中,代码如下:
[cpp] view plain copy
  1. void mt_mt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level)  
  2. {  
  3.     struct mt65xx_led_data *led_data =  
  4.             container_of(led_cdev, struct mt65xx_led_data, cdev);  
  5.               
  6. #ifdef LED_INCREASE_LED_LEVEL_MTKPATCH  
  7.     if (level >> LED_RESERVEBIT_SHIFT) {  
  8.         if (LED_RESERVEBIT_PATTERN != (level >> LED_RESERVEBIT_SHIFT)) {  
  9.             return;  
  10.         }  
  11.           
  12.         if (MT65XX_LED_MODE_CUST_BLS_PWM != led_data->cust.mode) {  
  13.             return;  
  14.         }  
  15.           
  16.         /* ... */  
  17.     } else {  
  18.         if (led_data->level != level) {  
  19.             led_data->level = level;  
  20.             if (strcmp(led_data->cust.name, "lcd-backlight") != 0) {  
  21.                 schedule_work(&led_data->work);  
  22.             } else {  
  23.                 if (MT65XX_LED_MODE_CUST_BLS_PWM == led_data->cust.mode) {  
  24.                     mt_mt65xx_led_set_cust(&led_data->cust, ((((1 << MT_LED_INTERNAL_LEVEL_BIT_CNT) - 1)*level + 127)/255));  
  25.                 } else {  
  26.                     mt_mt65xx_led_set_cust(&led_data->cust, led_data->level);  
  27.                 }  
  28.             }  
  29.         }  
  30.     }  
  31. #endif  
  32. }  
在这个函数中,"if (level >> LED_RESERVEBIT_SHIFT)"中的if部分是不会被执行的,因为对于lcd背光来说,level值是不会超过255的。然后判断是否同之前的level值相同,如果不相同,则是不会被设置的,这一点在hal层也有这个判断。如果不是lcd背光,则执行led_data中的工作队列work。如果是lcd背光呢,则这里又判断它的mode是否是MT65XX_LED_MODE_CUST_BLS_PWM,如果是MT65XX_LED_MODE_CUST_BLS_PWM,则会对level值做下处理,最后他们都调用的是mt_mt65xx_led_set_cust函数。

如果mode为MT65XX_LED_MODE_CUST_BLS_PWM,那么这个level值计算公式是怎样的呢,为: ((( 1 << 10) - 1)*level + 127 ) / 255,可以看到这个值会明显增大很多。

lcd背光调用的是mt_mt65xx_led_set_cust函数,而对于普通的led,最终也是调用的mt_mt65xx_led_set_cust这个函数:
[cpp] view plain copy
  1. void mt_mt65xx_led_work(struct work_struct *work)  
  2. {  
  3.     mt_mt65xx_led_set_cust(&led_data->cust, led_data->level);  
  4. }  

mt_mt65xx_led_set_cust代码如下:
[cpp] view plain copy
  1. int mt_mt65xx_led_set_cust(struct cust_mt65xx_led *cust, int level)  
  2. {  
  3.     switch (cust->mode) {  
  4.     case MT65XX_LED_MODE_PWM:  
  5.         if (strcmp(cust->name, "lcd-backlight") == 0) {  
  6.             if (level == 0) {  
  7.                 mt_pwm_disable(cust->data, cust->config_data.pmic_pad);  
  8.             } else {  
  9.                 if (BacklightLevelSupport == BACKLIGHT_LEVEL_PWM_256_SUPPORT)  
  10.                     level = brightness_mapping(tmp_level);  
  11.                 else  
  12.                     level = brightness_mapto64(tmp_level);  
  13.                 mt_backlight_set_pwm(cust->data, level, bl_div_hal, &cust->config_data);  
  14.             }  
  15.             bl_duty_hal = level;  
  16.         } else {  
  17.             if (level == 0) {  
  18.                 led_tmp_setting.nled_mode = NLED_OFF;  
  19.                 mt_led_set_pwm(cust->data, &led_tmp_setting);  
  20.                 mt_pwm_disable(cust->data, cust->config_data.pmic_pad);  
  21.             } else {  
  22.                 led_tmp_setting.nled_mode = NLED_ON;  
  23.                 mt_led_set_pwm(cust->data,&led_tmp_setting);  
  24.             }  
  25.         }  
  26.         return 1;  
  27.     case MT65XX_LED_MODE_GPIO:  
  28.         return ((cust_set_brightness)(cust->data))(level);  
  29.     case MT65XX_LED_MODE_PMIC:  
  30.         return mt_brightness_set_pmic(cust->data, level, bl_div_hal);  
  31.     case MT65XX_LED_MODE_CUST_LCM:  
  32.         return ((cust_brightness_set)(cust->data))(level, bl_div_hal);  
  33.     case MT65XX_LED_MODE_CUST_BLS_PWM:  
  34.         return ((cust_set_brightness)(cust->data))(level);  
  35.     case MT65XX_LED_MODE_NONE:  
  36.     default:  
  37.         break;  
  38.     }  
  39.     return -1;  
  40. }  
ok,我们一个一个来看。先来看背光的MT65XX_LED_MODE_CUST_BLS_PWM,调用的cust->data这个指针函数,在定义cust_led_list这个数组时,它被赋值成了disp_bls_set_backlight,定义如下(mediatek/platform/mt6582/kernel/drivers/dispsys/ddp_bls.c):
[cpp] view plain copy
  1. #if !defined(MTK_AAL_SUPPORT)  
  2. int disp_bls_set_backlight(unsigned int level)  
  3. {  
  4.     mapped_level = brightness_mapping(level);  
  5.     DISP_REG_SET(DISP_REG_BLS_PWM_DUTY, mapped_level);  
  6.       
  7.     if (level != 0) {  
  8.         regVal = DISP_REG_GET(DISP_REG_BLS_EN);  
  9.         if (!(regVal & 0x10000)) {  
  10.             DISP_REG_SET(DISP_REG_BLS_EN, regVal | 0x10000);  
  11.         }  
  12.     } else {  
  13.         regVal = DISP_REG_GET(DISP_REG_BLS_EN);  
  14.         if (regVal & 0x10000)  
  15.             DISP_REG_SET(DISP_REG_BLS_EN, regVal & 0xffffffff);  
  16.     }  
  17. }  
  18. #endif  
注意:要使用这段代码,那么在ProjectConfig.mk中MTK_AAL_SUPPORT这个宏不应该被配置的。
首先将level做一下映射,brightness_mapping函数定义如下:
[cpp] view plain copy
  1. unsigned int brightness_mapping(unsigned int level)  
  2. {  
  3.     unsigned int mapped_level;  
  4.     mapped_level = level;  
  5.       
  6.     return mapped_level;  
  7. }  
还是返回的原来的值,没有做映射处理(注意版本不一样,这里处理结果可能也不一样)。

然后将这个值写入到寄存器DISP_REG_BLS_PWM_DUTY中,如果level不为0,则使能pwm输出,如果level为0,则pwm禁止输出,关闭lcd背光。

再来看MT65XX_LED_MODE_PMIC,最终调用的电源管理那边的操作函数,这里也不在去细看了。

如果是使用MT65XX_LED_MODE_GPIO呢,那么也是需要自定义操作gpio口的函数。

关于led部分代码就先到这里,全文完。