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

最簡單的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](https://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 前](https://img-blog.csdn.net/20170807223111237?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0NDM5ODk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
            ![echo 後](https://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,代碼如下:

  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燈,代碼如下:
  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的背光亮度,這部分代碼如下:
  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中。首先是模塊初始化和卸載函數(注:省略了部分代碼,只提取出了主幹代碼):
  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中:
  1. static struct platform_device mt65xx_leds_device = {  
  2.     .name   = "leds-mt65xx",  
  3.     .id     = -1  
  4. };  
再來看probe函數:
  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中:
  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中提供了這麼一個示例:
  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這個函數。
  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中,代碼如下:
  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這個函數:
  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代碼如下:
  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):
  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函數定義如下:
  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部分代碼就先到這裏,全文完。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章