移动设备的休眠唤醒功能,为了省电而生,当然,你也可以在休眠的时候做一些差异化的功能。下面就介绍如何在高通平台中根据显示屏的状态,修改设备的工作状态。本文内容参考自sm6350, kernel 4.19

1:设备的dtsi属性设置示例:
xxx-qrd.dtst
&qupv3_se8_i2c {
#address-cells = <1>;
#size-cells = <0>;

status = "ok";
qcom,i2c-touch-active = "focaltech,fts";focaltech@38 {compatible = "focaltech,fts";...panel = <&dsi_rm692d7_visionox_amoled_cmd>;
};

};

2:内核公共数据结构
notifier.h
typedef int (*notifier_fn_t)(struct notifier_block *nb,
unsigned long action, void *data);

struct notifier_block {
notifier_fn_t notifier_call;
struct notifier_block __rcu *next;
int priority;
};

struct blocking_notifier_head {
struct rw_semaphore rwsem;
struct notifier_block __rcu *head;
};

3:高通私有数据结构和函数,及相关显示驱动
drm_panel.h
/**

  • struct drm_panel - DRM panel object

  • @drm: DRM device owning the panel

  • @connector: DRM connector that the panel is attached to

  • @dev: parent device of the panel

  • @funcs: operations that can be performed on the panel

  • @list: panel entry in registry

  • @nh: panel notifier list head
    */
    struct drm_panel {
    struct drm_device *drm;
    struct drm_connector *connector;
    struct device *dev;

    const struct drm_panel_funcs *funcs;

    struct list_head list;

    /**

    • @nh:
    • panel notifier list head
      */
      struct blocking_notifier_head nh;
      };

drm_panel.c
static LIST_HEAD(panel_list); //定义屏的全局list

/**

  • drm_panel_init - initialize a panel
  • @panel: DRM panel
  • Sets up internal fields of the panel so that it can subsequently be added
  • to the registry.
    */
    void drm_panel_init(struct drm_panel *panel)
    {
    INIT_LIST_HEAD(&panel->list);
    BLOCKING_INIT_NOTIFIER_HEAD(&panel->nh);
    }
    EXPORT_SYMBOL(drm_panel_init);

/**

  • drm_panel_add - add a panel to the global registry

  • @panel: panel to add

  • Add a panel to the global registry so that it can be looked up by display

  • drivers.

  • Return: 0 on success or a negative error code on failure.
    */
    int drm_panel_add(struct drm_panel *panel)
    {
    mutex_lock(&panel_lock);
    list_add_tail(&panel->list, &panel_list);
    mutex_unlock(&panel_lock);

    return 0;
    }
    EXPORT_SYMBOL(drm_panel_add);

/**

  • of_drm_find_panel - look up a panel using a device tree node

  • @np: device tree node of the panel

  • Searches the set of registered panels for one that matches the given device

  • tree node. If a matching panel is found, return a pointer to it.

  • Return: A pointer to the panel registered for the specified device tree

  • node or an ERR_PTR() if no panel matching the device tree node can be found.

  • Possible error codes returned by this function:

    • EPROBE_DEFER: the panel device has not been probed yet, and the caller
  • should retry later

    • ENODEV: the device is not available (status != “okay” or “ok”)
      */
      struct drm_panel *of_drm_find_panel(const struct device_node *np)
      {
      struct drm_panel *panel;

    if (!of_device_is_available(np))
    return ERR_PTR(-ENODEV);

    mutex_lock(&panel_lock);

    list_for_each_entry(panel, &panel_list, list) {
    if (panel->dev->of_node == np) {
    mutex_unlock(&panel_lock);
    return panel;
    }
    }

    mutex_unlock(&panel_lock);
    return ERR_PTR(-EPROBE_DEFER);
    }
    EXPORT_SYMBOL(of_drm_find_panel);

int drm_panel_notifier_register(struct drm_panel *panel,
struct notifier_block *nb)
{
return blocking_notifier_chain_register(&panel->nh, nb);
}
EXPORT_SYMBOL_GPL(drm_panel_notifier_register);

int drm_panel_notifier_unregister(struct drm_panel *panel,
struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&panel->nh, nb);
}
EXPORT_SYMBOL_GPL(drm_panel_notifier_unregister);

dsi_panel.c  //屏驱动
struct dsi_panel *dsi_panel_get(struct device *parent,
struct device_node *of_node,
struct device_node *parser_node,
const char *type,
int topology_override)
{

drm_panel_init(&panel->drm_panel); //初始化drm_panel结构体

rc = drm_panel_add(&panel->drm_panel); //将panel添加到全局链表中,以便后续查找,使用

}

sde_kms.c
static void _sde_kms_drm_check_dpms(struct drm_atomic_state *old_state,
unsigned long event) //屏resume函数
{

if (connector->panel)
drm_panel_notifier_call_chain(connector->panel, event, &notifier_data);

}

4:实例:TouchPanel休眠唤醒功能的注册
focaltech_core.c //tp驱动
static int fts_ts_check_dt(struct device_node *np)
{

panel = of_drm_find_panel(node);  //蓝领
of_node_put(node);
if (!IS_ERR(panel)) {
active_panel = panel;
return 0;
}

}
static int fts_ts_check_default_tp(struct device_node *dt, const char *prop)
{

for (i = 0; i < count; i++) {
active = active_tp[i];
if (active != NULL) {
tmp = of_device_is_compatible(dt, active);
if (tmp > 0)
score++;
}
}

}

static int fts_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{

if (fts_ts_check_dt(dp)) { //通过device_node,查找对应屏struct drm_panel并赋值给×active_panel,if yes,返回"0";else 返回“-ENODEV”
if (!fts_ts_check_default_tp(dp, “qcom,i2c-touch-active”)) //如果没有找到drm_panel,会比较本tp设备节点competibel属性值是否与父节点字符串对应属性值有相同,
//if yes, 挂入延时probe链表,重新probe(保证不会因屏驱动probe慢而引起tp probe失败), else, 退出probe;
ret = -EPROBE_DEFER; //驱动需延时重新probe标记
else
ret = -ENODEV;

    return ret;
}...
if (ts_data->ts_workqueue) {INIT_WORK(&ts_data->resume_work, fts_resume_work);
}
ts_data->fb_notif.notifier_call = fb_notifier_callback; //回调函数初始化if (active_panel &&drm_panel_notifier_register(active_panel,  //将tp的notifier挂载到屏的阻塞式通知链中,注:drm_panel_notifier_register()为对应注销函数&ts_data->fb_notif) < 0)FTS_ERROR("register notifier failed!\n");...

}

TouchPanel--Qcom DRM休眠唤醒通知链的注册及回调流程相关推荐

  1. 深入理解Linux网路技术内幕学习笔记第四章:通知链

    第四章:通知链 内核很多子系统之间具有很强的依赖性,其中一个子系统侦测到的或者产生的事件,其他子系统可能都感兴趣,为了实现这种需求,Linux使用了通知链.通知链只在内核子系统之间使用. 通知链就是一 ...

  2. Linux内核源码——通知链(notifier chain)

    写在前面的话: 刚入手Linux驱动的时候,各种Linux内核的机制是我们需要搬起的一块大砖块.搬砖的过程中,我发现自己不能很好的理解相关的业务驱动的很大的一个原因就是对内核的基本机制掌握不太准确.刚 ...

  3. Linux内核通知链机制的原理及实现【转】

    转自:http://www.cnblogs.com/armlinux/archive/2011/11/11/2396781.html 一.概念: 大多数内核子系统都是相互独立的,因此某个子系统可能对其 ...

  4. Linux 内核通知链和例程代码

    概念 大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,Linux内核提供了通知链的机制.通知链表只 ...

  5. Linux内核基础--事件通知链(notifier chain)【转】

    转自:http://blog.csdn.net/wuhzossibility/article/details/8079025 内核通知链 1.1. 概述 Linux内核中各个子系统相互依赖,当其中某个 ...

  6. notifier通知链机制

    1. 目的 Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,就必须使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施.为满足这样的需求,内核实现了事件通知链机制 ...

  7. 内核通知链(网络子系统为例)

    概念 1.Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,就必须使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施.为满足这样的需求,内核实现了事件通知链机制( ...

  8. linux 网络函数调用链,Linux通知链机制及实例

    Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,要使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施.内核实现了事件通知链机制(notification cha ...

  9. IPv6路由FIB通知链

    在网络命名空间初始化时,初始化fib通知链操作链表.此函数位于文件net/core/fib_notifier.c中,也就是IPv4和IPv6共用. static int __net_init fib_ ...

  10. android休眠唤醒驱动流程分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/11777501 标准linux休眠过程: l        power managemen ...

最新文章

  1. WDS Services Can't Start
  2. 【旧文新读】解释“闭包”需要几行代码?
  3. 为物联网产业化发展提供坚实保障
  4. [转载]MongoDB开发学习 经典入门
  5. 使用 json_serializable (flutter packages pub run build_runner build) 问题
  6. 关于 Qt 5,你所需要了解的基础知识
  7. mysql数据库工程师网易微专业_网易MySQL数据库工程师微专业学习笔记(五)
  8. Android无线调试——抛开USB数据线
  9. 作业 利用单选框控制图片的显示
  10. 重磅分享:一份关于车贷的政策性文件分享
  11. 安卓手机老是自动保存图片_Redmi K30 Pro自动亮度调节和iPhone基本一致,安卓手机的大进步...
  12. 什么样的生意一本万利?
  13. BZOJ2655 calc(动态规划+拉格朗日插值法)
  14. perl语言入门:全局变量和私有变量
  15. 2022微软苏州Software Engineer校招暑期实习生二面
  16. VMware安装虚拟机操作步骤[史上最详细]
  17. Springboot @Aspect
  18. 修真院教学模式四大体系之技能体系
  19. phpmyadmin没有接收到要导入的数据.可能是文件名没有提交,也可能是文件大小超出 PHP 限制.
  20. ABBYY FineReader 14创建PDF文档功能解析

热门文章

  1. 深度置信网络 Deep belief network
  2. libcrypto yum 安装_CentOS升级OpenSSL至OpenSSL 1.1.0f版本其中有遇到libcrypto.so的问题...
  3. 【博客1】缤果Qt串口网络蓝牙调试助手V3.1.0.9(高级篇)
  4. JAVA实现EXCEL公式专题(七)——统计函数
  5. 设计模式入门进阶深入书籍汇总
  6. 人大金仓数据库工程师培训实战教程(同步复制、读写分离、集群高可用)
  7. navicat中文破解版,navicat for mysql10.0.11简体中文破解版
  8. css规则、选择器(基础、复合)/选择器优先级
  9. 宾馆客房管理系统Mysql数据库课程设计
  10. 人脸识别系统 讲解以及环境搭建(Java 附源码)