该系列文章总目录链接与各部分简介: Android Qcom Display学习(零)
在项目中我们经常会遇到需要兼容lcd和tp的情况,如果是不同i2c地址的touch,没有probe成功也就根本不过去用,所以one lcd mutil touch的情况暂时还没有遇到过去做区分的,那项目中主要遇到的就是以下这种情况one touch mutil lcd
这种情况下,lcd本身通过dsi读取的id就能区分不同型号的panel,xbl会传入cmdline,lcd在模块注册就会去解析传参并注册到kernel中,tp在调用of_drm_find_panel(node)获得注册到kernel中的panel型号与devicetree中的panel型号进行比对绑定
dtsi:
atmel_maxtouch_ts@4a {
panel = <&dsi_hx8399_1080_video &dsi_ili9881c_720p_video>;
kernel:
count = of_count_phandle_with_args(np, "panel", NULL);
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "panel", i);
panel = of_drm_find_panel(node); //↓↓
of_node_put(node);
if (!IS_ERR(panel)) {
return panel;
}
}
drm_panel_notifier_register(data->active_panel, &data->fb_notif);
那项目中可能不仅仅是支持多个panel基础功能,需要不同的panel对应的tp支持不同的cfg(tunning的配置,触摸灵敏度或者旋转等)
devicetree:
atmel_maxtouch_ts@4a {
/* root node */
tp_a@0x0000 { /* child node */
board_version = "0x0000";
/* root node */
pnl_a@0x001 { /* child node */
pnl-name = "hx8399";
pnl-cfg = "mxt640u.raw";
atmel,display-coords = <0 0 1080 1920>;
atmel,panel-coords = <0 0 1080 1920>;
};
pnl_b@0x002 { /* child node */
pnl-name = "ili9881c";
pnl-cfg = "mxt640u_version2.raw";
atmel,display-coords = <0 0 720 1280>;
atmel,panel-coords = <0 0 720 1280>;
};
};
tp_b@0x0001{ /*child node*/
board_version = "0x0001";
...
kernel:
static int mxt_get_pnl_fw_cfg(struct device *dev, struct mxt_platform_data *pdata, int layer, struct device_node *root){
{
int index = 0;
int error = -EINVAL;
struct device_node *child;
u32 coords[MXT_COORDS_ARR_SIZE];
dev_info(dev, "enter %s, layer = %d\n", __func__,layer);
for_each_child_of_node(root, child) {
if(!layer) { //Root
//can add to compatible more;like project versin
continue;
} else if (layer == 1) { //parse panel name
static const char *pnl_name = NULL;
error = of_property_read_string(child, "pnl-name", &pnl_name);
if (error && (error != -EINVAL)) {
dev_err(dev, "Unable to read pnl name\n");
}
dev_dbg(dev,"%s: pnl_name = %s lcm_panel_name = %s\n",__func__,pnl_name,lcm_panel_name);
/* select panel config according to panel name */
if ( NULL == strstr (lcm_panel_name, pnl_name) ) {
continue;
}
}
error = mxt_get_pnl_fw_cfg(dev, pdata, layer+1, child);
if (!error) {
dev_dbg(dev,"%s: already get all information\n", __func__);
goto out;
}
error = of_property_read_string (child, "pnl-cfg", &pdata->cfg_name);
dev_info(dev,"%s: cfg_name = %s\n", __func__, pdata->cfg_name);
if (error && (error != -EINVAL)) {
dev_err(dev, "Unable to read cfg name\n");
goto out;
}
error = of_property_read_string(child, "pnl-fw", &pdata->fw_name);
dev_info(dev,"%s: fw_name = %s\n", __func__, pdata->fw_name);
if (error && (error != -EINVAL)) {
dev_err(dev, "Unable to read fw name\n");
goto out;
}
...
break;
}
out:
dev_info(dev, "leave %s, layer =%d\n", __func__, layer);
return error;
利用for_each_child_of_node对devicetree进行遍历,可扩展。上述案例利用两层循环,如果version不对的话,则会跳出循环到下一个childnode(tp_b@0x0001);如果version是对的话,那么会调用mxt_get_pnl_fw_cfg进入下一级循环,rootnode会变,layer+1,解析第一个childnode(pnl_a@0x0001)的panel name进行比较,如果对的话,进一步解析获取全部信息(主要时cfg文件和firmware用于更新);如果不对的跳出循环进入下一个childnode(pnl_b@0x0002);再对panel name进行比较;利用devicetree可以在其他项目中也能很容易的做到兼容,一套kernel驱动不用修改;所以后续跟项目有关的在devicetree中做标记,防止驱动冗余,可读性差。