在梳理代码时,感觉 MTK 的代码中公共部分和客制化部分分的还是很清楚的。
首先说明一下文档的结构,我们先介绍我们客制化的地方,因为这个才是我们实际调试及解决 bug 时真正要关心的,而平台端不需要客制化的代码只需要梳理清楚就行。
背光流程中,客制化与否的分界文件是
cust_leds.c (vendor\vendor\mediatek\proprietary\bootable\bootloader\lk\target$(project))
其中
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
这个结构体就是客制化led子系统(包括呼吸灯、键盘灯、按键灯、背光等)中的模块具体调用方式的,比如
- 1
- 1
第一个成员就是定义操作的模块, lcd-backlight 就代表背光,
第二个成员表示对该模块的操作方式,mode,
第三个成员就是代表控制该模块的具体函数,
第四个成员就是代表一些配置, config;
这些成员的含义可以通过 cust_mt65xx_led 的声明来得知,在 cust_leds.h 中。
我们需要根据项目需要客制化模块背光控制函数,可以有很多选择,具体分析下函数怎么执行就行。
在背光控制中,有很多方式比如 disp_bls_set_backlight 、primary_display_setbacklight 等等,网上可以搜到的比较多的是 disp_bls_set_backlight ,客制化为这个函数的朋友可以搜一下,由于我没有看过primary_display_setbacklight 的相关介绍,正好项目中用到了,那我就写一下这种控制背光方式的原理。
primary_display_setbacklight 主要是针对设置了 cabc (根据画面内容实时调节背光亮度)的项目执行的背光控制函数。
我们来看
primary_display_setbacklight 函数 (kernel-3.18\kernel-3.18\drivers\misc\mediatek\video\mt6735\primary_display.c)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
到这里就直接调到底层的操作了,客制化部分就结束了。
然后我们看一下平台端走的客制化控制函数之前怎么走的。
Led 子系统的驱动文件是 leds_drv.c,
模块注册等等都是字符设备注册方式:
驱动结构体 platform_driver mt65xx_leds_driver 和设备结构体 platform_device mt65xx_leds_device 的name 相同时就会触发探测函数 mt65xx_leds_probe
我们来看这个函数的内容:
第一个重要的函数就是 struct cust_mt65xx_led * cust_led_list = mt_get_cust_led_list();
调用 mt_get_cust_led_list(),这个函数调用到 leds.c 中的
struct cust_mt65xx_led *mt_get_cust_led_list(void),再调用到 leds.c 中的
struct cust_mt65xx_led *get_cust_led_dtsi(void)
这个函数就厉害了,我们可以看到这个函数的注释:get the leds info from device tree,即从 devicetree 读取 leds 的节点信息。
- 1
- 1
首先我们看到申请了一个结构体,内存大小是前面我们需要客制化的结构体 cust_mt65xx_led 的大小。
之后开始遍历 led 子系统中的各个模块,每个模块都会执行下列步骤:
pled_dtsi[i].name= leds_name[i]; 得到模块名称
- 1
- 1
读取节点信息, of_find_compatible_node 函数式 device tree 读取节点信息的函数。
- 1
- 1
读取模块工作模式,赋值给 mode;
- 1
- 1
读取模块模块控制函数,赋值给 data;
- 1
- 1
读取模块配置参数,赋值给 config;
switch(pled_dtsi[i].mode)
然后根据工作模式,
- 1
- 2
- 3
- 1
- 2
- 3
选取并指定模块控制方式函数。
这里我们客制化的是 MT65XX_LED_MODE_CUST_LCM,所以背光控制函数指定为mtkfb_set_backlight_level。
到这里第一个重要的函数结束,继续回到 leds_drv.c 走 probe 函数,
i2c_add_driver(&led_i2c_driver) ;注册 i2c 驱动
get_div_array(); 获取分频信息,这个具体的功能可能跟 pwm 配置有关;
然后又进行一次 leds 子系统各模块的遍历,将上面读取的 device tree 中的信息赋值给 g_leds_data 数组,只不过这个数组是 mt65xx_led_data 类型,会有更多的操作函数
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
这样的话控制背光亮度就可以确定为 mt65xx_led_set;
我们来看这个函数:
static void mt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level)(leds_drv.c)
传入参数是设备和亮度等级,开始!
node =of_find_compatible_node(NULL, NULL, “mediatek,lcd-backlight”);读取device tree中lcd-backlight 的信息,即背光;
前面是对对 level 的一些普通的判断操作,包括限制大小,然后
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
根据亮度等级置高置低引脚,这里可能是为了省电,在亮度为 0 时直接关闭那个 pin 脚,厉害了。
然后结束就是 mt_mt65xx_led_set(led_cdev,level);
这个就是在对传进的 level 参数处理完成之后再次传入一个背光控制函数,
我们看 void mt_mt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level)
#ifdef CONFIG_MTK_AAL_SUPPORT
使用 AAl 这个宏来控制代码,项目中没有打开这个宏,就走 else 里的代码
然后就是一番逻辑判断之后
mt_mt65xx_led_set_cust(&led_data->cust,level);
在看 int mt_mt65xx_led_set_cust(struct cust_mt65xx_led *cust, int level) 这个函数:
switch(cust->mode) 判断 device tree 中的背光控制模式,
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
这里最后一句话 ((cust_brightness_set)(cust->data)) 是使用 typedef 进行代码简化,想深究的话就搜一下 typedef 的用法
((cust_brightness_set)(cust->data)) (level, bl_div_hal); 这句话的意思就是执行
客制化的模块控制函数 primary_display_setbacklight();
到这里就和前面的客制化内容相互对接了。
其实这个 switch(cust->mode) 就是为了根据客制化的 mode 来判断是走平台的背光控制还是走 lcd 本身的背光控制函数