RK3568平台(背光篇)背光驱动代码分析
一.背光驱动设备树DTS
backlight: backlight {compatible = "pwm-backlight";pwms = <&pwm1 0 5555555 1>;brightness-levels = <77 77 78 78 79 79 80 8182 83 84 85 86 87 87 8888 89 90 90 91 91 92 9394 94 95 95 96 96 97 9798 98 99 99 100 100 101 101102 103 104 104 105 106 107 107108 108 109 109 110 111 112 113114 115 116 116 117 117 118 118119 119 120 121 122 123 124 124125 125 126 126 127 127 128 128129 129 130 130 131 131 132 132133 133 134 134 135 135 136 136137 137 138 138 139 139 140 141142 142 143 144 145 146 146 147147 148 148 149 149 150 151 151152 153 153 154 154 155 156 156157 158 158 159 160 161 162 162163 163 164 164 165 165 166 166167 168 168 169 170 171 172 172173 174 175 175 176 177 178 179 180 181 182 182 183 184 185 186 187 188 189 190 190 191 192 193 194 194 195 196 197 198 199 199 200 201 202 203 204 204 205 206 207 208 209 210 211 211 212 213 214 215 216 216 217 217 218 219 219 220 220 221 222 223 224 224 225 225 226 227 228 229 229 230 231 232 232 233 234 235 236 237 238 239 239 240 240 241 242 242 243 244 245 246 246 247 247 248 249 250 251 251 252 253 254 255>;default-brightness-level = <235>;
};
二.背光驱动代码分析
背光驱动部分代码路径:kernel-5.10\drivers\video\backlight\pwm_bl.c
背光驱动入口部分:
static struct platform_driver pwm_backlight_driver = {.driver = {.name = "pwm-backlight",.pm = &pwm_backlight_pm_ops,.of_match_table = of_match_ptr(pwm_backlight_of_match),},.probe = pwm_backlight_probe,.remove = pwm_backlight_remove,.shutdown = pwm_backlight_shutdown,
};module_platform_driver(pwm_backlight_driver);MODULE_DESCRIPTION("PWM based Backlight Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:pwm-backlight");
先看驱动适配函数pwm_backlight_probe:
static int pwm_backlight_probe(struct platform_device *pdev)
{struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev);struct platform_pwm_backlight_data defdata;struct backlight_properties props;struct backlight_device *bl;struct device_node *node = pdev->dev.of_node;struct pwm_bl_data *pb;struct pwm_args pargs;int ret;if (!data) {ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);if (ret < 0) {dev_err(&pdev->dev, "failed to find platform data\n");return ret;}data = &defdata;}if (data->init) {ret = data->init(&pdev->dev);if (ret < 0)return ret;}pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);if (!pb) {ret = -ENOMEM;goto err_alloc;}if (data->levels) {unsigned int i;for (i = 0; i <= data->max_brightness; i++)if (data->levels[i] > pb->scale)pb->scale = data->levels[i];pb->levels = data->levels;} elsepb->scale = data->max_brightness;pb->notify = data->notify;pb->notify_after = data->notify_after;pb->check_fb = data->check_fb;pb->exit = data->exit;pb->dev = &pdev->dev;pb->enabled = false;pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",GPIOD_ASIS);if (IS_ERR(pb->enable_gpio)) {ret = PTR_ERR(pb->enable_gpio);goto err_alloc;}/** Compatibility fallback for drivers still using the integer GPIO* platform data. Must go away soon.*/if (!pb->enable_gpio && gpio_is_valid(data->enable_gpio)) {ret = devm_gpio_request_one(&pdev->dev, data->enable_gpio,GPIOF_OUT_INIT_HIGH, "enable");if (ret < 0) {dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n",data->enable_gpio, ret);goto err_alloc;}pb->enable_gpio = gpio_to_desc(data->enable_gpio);}/** If the GPIO is not known to be already configured as output, that* is, if gpiod_get_direction returns either GPIOF_DIR_IN or -EINVAL,* change the direction to output and set the GPIO as active.* Do not force the GPIO to active when it was already output as it* could cause backlight flickering or we would enable the backlight too* early. Leave the decision of the initial backlight state for later.*/if (pb->enable_gpio &&gpiod_get_direction(pb->enable_gpio) != GPIOF_DIR_OUT)gpiod_direction_output(pb->enable_gpio, 1);pb->power_supply = devm_regulator_get(&pdev->dev, "power");if (IS_ERR(pb->power_supply)) {ret = PTR_ERR(pb->power_supply);goto err_alloc;}pb->pwm = devm_pwm_get(&pdev->dev, NULL);if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER && !node) {dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");pb->legacy = true;pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");}if (IS_ERR(pb->pwm)) {ret = PTR_ERR(pb->pwm);if (ret != -EPROBE_DEFER)dev_err(&pdev->dev, "unable to request PWM\n");goto err_alloc;}dev_dbg(&pdev->dev, "got pwm for backlight\n");/** FIXME: pwm_apply_args() should be removed when switching to* the atomic PWM API.*/pwm_apply_args(pb->pwm);/** The DT case will set the pwm_period_ns field to 0 and store the* period, parsed from the DT, in the PWM device. For the non-DT case,* set the period from platform data if it has not already been set* via the PWM lookup table.*/pwm_get_args(pb->pwm, &pargs);pb->period = pargs.period;if (!pb->period && (data->pwm_period_ns > 0))pb->period = data->pwm_period_ns;pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale);memset(&props, 0, sizeof(struct backlight_properties));props.type = BACKLIGHT_RAW;props.max_brightness = data->max_brightness;bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,&pwm_backlight_ops, &props);if (IS_ERR(bl)) {dev_err(&pdev->dev, "failed to register backlight\n");ret = PTR_ERR(bl);if (pb->legacy)pwm_free(pb->pwm);goto err_alloc;}if (data->dft_brightness > data->max_brightness) {dev_warn(&pdev->dev,"invalid default brightness level: %u, using %u\n",data->dft_brightness, data->max_brightness);data->dft_brightness = data->max_brightness;}bl->props.brightness = data->dft_brightness;bl->props.power = pwm_backlight_initial_power_state(pb);backlight_update_status(bl);platform_set_drvdata(pdev, bl);return 0;err_alloc:if (data->exit)data->exit(&pdev->dev);return ret;
}
probe里有几个重要的函数,这里按照调用顺序,依次进行阐述:
pwm_backlight_probe-> pwm_backlight_parse_dt //拿到dts里定义的brightness-levels和default-brightness-level,前者用来应用层控制不同的背光亮度,后者在初始化时会使能一个默认的背光亮度-> devm_gpiod_get_optional //实际上就是封装了 gpio_request_one-> devm_gpio_request_one //申请背光使能 gpio-> devm_pwm_get -> /drivers/pwm/core.c //获得一个pwm-> pwm_request //申请pwm,防止其他驱动也会使用.-> backlight_device_register -> /drivers/video/baklight/backlight.c //注册标准背光设备static const struct backlight_ops pwm_backlight_ops = {.update_status = pwm_backlight_update_status,.check_fb = pwm_backlight_check_fb,};-> pwm_backlight_update_status-> compute_duty_cycle //计算占空比-> pwm_backlight_power_on //enable背光-> backlight_update_status -> //用默认值更新.
compute_duty_cycle函数计算占空比:
static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness)
{/*一般情况下这个值都为0*/unsigned int lth = pb->lth_brightness;/*占空比*/int duty_cycle;/*pb->levels这个表格就是从dts节点brightness-levels中获取的,假设进来的参数brightness是254,那么得到的duty_cycle就是1,如果没有这个表格,那么就直接是进来的亮度值.*/if (pb->levels)duty_cycle = pb->levels[brightness];elseduty_cycle = brightness;/*假设这里lth是0,那么公式就是duty_cycle * pb->period / pb->scalepb->period也就是dts节点 pwms 的第三个参数周期值为 25000pb->scale为pb->levels数组中的最大值所以这个公式就是按照将Android的纯数值转换成事件周期值对应的占空比.*/return (duty_cycle * (pb->period - lth) / pb->scale) + lth;
}
pwm_backlight_power_on 函数通过去拉背光的gpio enable背光
static void pwm_backlight_power_on(struct pwm_bl_data *pb)
{struct pwm_state state;int err;pwm_get_state(pb->pwm, &state);if (pb->enabled)return;err = regulator_enable(pb->power_supply);if (err < 0)dev_err(pb->dev, "failed to enable power supply\n");state.enabled = true;pwm_apply_state(pb->pwm, &state);if (pb->post_pwm_on_delay)msleep(pb->post_pwm_on_delay);if (pb->enable_gpio)gpiod_set_value(pb->enable_gpio, 1); pb->enabled = true;
}
LCD背光驱动,导出给应用层控制背光的brightness、bl_power、actual_brightness等节点
路径:kernel-5.10\drivers\video\backlight\backlight.c
再backlight.c文件里面会给应用层控制背光的brightness、bl_power、actual_brightness等节点
对应于/sys/class/backlight,提供属性和操作函数。
/sys/class/backlight/lcd_backlight@0
cat max_brightness //获取最大的亮度:100
cat actual_brightness //获取实际的亮度:80
echo 100 > brightness //设置亮度为100
echo 80 > brightness //设置亮度为80
static ssize_t bl_power_show(struct device *dev, struct device_attribute *attr,char *buf)
{struct backlight_device *bd = to_backlight_device(dev);return sprintf(buf, "%d\n", bd->props.power);
}static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{int rc;struct backlight_device *bd = to_backlight_device(dev);unsigned long power, old_power;rc = kstrtoul(buf, 0, &power);if (rc)return rc;rc = -ENXIO;mutex_lock(&bd->ops_lock);if (bd->ops) {pr_debug("set power to %lu\n", power);if (bd->props.power != power) {old_power = bd->props.power;bd->props.power = power;rc = backlight_update_status(bd);if (rc)bd->props.power = old_power;elserc = count;} else {rc = count;}}mutex_unlock(&bd->ops_lock);return rc;
}
static DEVICE_ATTR_RW(bl_power);static struct attribute *bl_device_attrs[] = {&dev_attr_bl_power.attr,&dev_attr_brightness.attr,&dev_attr_actual_brightness.attr,&dev_attr_max_brightness.attr,&dev_attr_scale.attr,&dev_attr_type.attr,NULL,
};
ATTRIBUTE_GROUPS(bl_device);
以bl_power为例:最终调用backlight_update_status()来调节背光。
三.应用程序调节背光
下面的两种方式都可以使用backlight节点来控制背光。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>#define LCD_BACKLIGHT "/sys/class/backlight/lcd_backlight@0/brightness"int main(int argc, char *argv[])
{
#if 0int fd;char *testwrite = "/sys/class/backlight/lcd_backlight@0/brightness";ssize_t len_w;char buf_w[] = "10";//if((fd = open("/sys/class/backlight/lcd_backlight@0/brightness", O_RDWR))<0){/* open()可以带2/3个参数 *///if((fd = open(testwrite,O_RDWR,0777))<0){if((fd = open(LCD_BACKLIGHT, O_RDWR, 0777)) <0 ){printf("open %s failed!\n",testwrite);}//len_w = write(fd, "99", 2);len_w = write(fd, buf_w, strlen(buf_w));if(len_w == -1){perror("write");} else{printf("write function ok!\n");}close(fd);#elseFILE * fp =fopen("/sys/class/backlight/lcd_backlight@0/brightness","w");if (fp == NULL)perror("export open filed");elsefprintf(fp,"%d",100);fclose(fp);
#endifreturn 0;
}
相关文章:

RK3568平台(背光篇)背光驱动代码分析
一.背光驱动设备树DTS backlight: backlight {compatible "pwm-backlight";pwms <&pwm1 0 5555555 1>;brightness-levels <77 77 78 78 79 79 80 8182 83 84 85 86 87 87 8888 89 90 90 91 91 92 9394 94 95 95 96 96 9…...

华为od统一考试B卷【比赛】python实现
def split_params(param_str): return list(map(int, param_str.split(,))) def main(): # 获取输入 target_str input().strip() # 输入验证,拆分并转换为整数 try: m, n split_params(target_str) except ValueError: print(-1) return # 检查 M 和 …...
Prometheus 监控接入规范
目录 一、目的 二、自定义监控指标定义规范 2.1 基本命名规范 2.1.1 指标命名规范 2.1.2 标签名称 2.2 控制基数 2.2.1 避免高基数标签 2.2.2 预定义标签集 2.2.3 动态数据的处理 2.2.4 评估与监控基数 2.2.5 降低历史数据的保留 2.2.6 适当使用 Histogram 和 Summa…...
优化 SQL 查询性能:深入理解 EXPLAIN 命令
优化 SQL 查询性能:深入理解 EXPLAIN 命令 在 MySQL 数据库管理中,优化 SQL 查询性能是确保高效数据处理的关键。EXPLAIN 命令是分析和优化 SQL 查询的强大工具,它帮助我们理解查询执行计划,从而找到性能瓶颈并进行优化。本文将详细解释 EXPLAIN 命令返回的各个列的含义,…...

@Mapper报红
检查pom.xml,导入 org.mybatis.spring.boot 依赖: <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency…...

shell综合小实验1-----查看系统硬件信息
echo命令的使用 1:echo -n 不换行 echo -n “我是个大聪明” #不换行输入我是大聪明 2:echo -e 开启颜色 echo -e "\03335m我是大聪明\033[0m" #用35m这种颜色输出我是大聪明然后关闭颜色显示, 30多是字体颜色,40多是…...

【过程管理】项目需求管理规程(Word原件)
在软件开发的过程中,开发人员与用户之间往往忽视有效的信息沟通,这常常导致开发出的软件无法满足用户的实际需求,进而引发不必要的返工。返工不仅为开发人员带来技术上的困扰,增加了人力和物力的消耗,还会对软件的整体…...
C# 不使用 `async` 和 `await` 的常见场景
虽然 async 和 await 是强大的异步编程工具,但在某些情况下,不使用它们可能更合适。以下是一些不使用 async 和 await 的常见场景: 方法是完全同步的: 如果方法中的所有操作都是同步的,并且没有异步调用,则…...
adb目录笔记《adb更新、进入开发者模式,adb查询packages、adb开启应用,查询进程、强制删除进程》
1.sideload模式 在需要安卓没有root权限的时候,可以使用adb reboot sideload命令进入sideload模式,之后运行对应文件 adb reboot sideload adb sideload <root.zip> 2.packages包查询、运行、删除 在需要查看安卓中packages包的名称时…...
VS2022 C++ EasyX EGE 吃豆人升级版
我是可爱的C小盆友(不要脸了),嘻嘻,等了这么久,吃豆人终于升级啦! 更新日志: 1.修复奇奇怪怪的bug 2.把敌人AI增强了一(hen)点(duo) 3.加入了…...

计算机图形学 | 动画模拟
动画模拟 布料模拟 质点弹簧系统: 红色部分很弱地阻挡对折 Steep connection FEM:有限元方法 粒子系统 粒子系统本质上就是在定义个体和群体的关系。 动画帧率 VR游戏要不晕需要达到90fps Forward Kinematics Inverse Kinematics 只告诉末端p点,中间…...
B2.3 Arm 内存模型定义
B2.3 Arm 内存模型定义 Arm 内存模型引入了以下几种关系: 内在关系 :例如,内在数据/控制/顺序依赖关系和内在翻译之前的关系,这些是源自指令语义的硬件要求。 之后关系 :例如,之后的连贯性和 TLB 之后的关系,这些关系在特定执行中发生这种方式,但在不同的执行中可以以…...

(javaweb)SpringBootWeb案例(毕业设计)案例--部门管理
目录 1.准备工作 2.部门管理--查询功能 3.前后端联调 3.部门管理--新增功能 1.准备工作 mapper数据访问层相当于dao层 根据页面原型和需求分析出接口文档--前后端必须遵循这种规范 大部分情况下 接口文档由后端人员来编写 前后端进行交互基于restful风格接口 http的请求方式…...

PCL 采样一致性模型介绍
采样一致性可以简单高效的检测出一些具有数学表达式的目标模型。PCL中的sample consensus模块中不仅包含各种的采样一致性估计方法,也包含一些已经编写好的数学模型,下面主要介绍一下PCL中的采样一致性模型。 1. 二维圆模型 pcl::SampleConsensusModelCircle2D< PointT …...
Unity手游开放大世界解决方案
开个新坑了,分享一个手游开放大世界的解决方案,也算是我开发研究了一年多的结果吧。之前项目需要,做了一整套的手游开放大世界解决方案,这里做一个总结归纳,将所需要的技术栈和解决方案等汇总。 这篇文章只是起头一个目…...

mysql B+ 树
问题: mysql innodb引擎 B树主键自增,插入数据时是从中间分裂,还是使用页尾部元素作为父节点的值然后添加一个新页,或者说主键连续自增,mysql有没有做这样的优化? 以下是Chat GPT给出的回答:...

Sublime Text常用快捷键大全
Sublime Text 是一款功能强大且广受欢迎的文本编辑器,其丰富的快捷键支持使得开发者能够更高效地编写和编辑代码。以下是 Sublime Text 中一些常用的快捷键,帮助你更加高效地使用这款工具: 功能分类快捷键 (Windows)快捷键 (Mac)新建文件Ctr…...
中成科信票务管理系统 TicketManager.ashx接口SQL注入漏洞复现 [附POC]
文章目录 中成科信票务管理系统 TicketManager.ashx接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议中成科信票务管理系统 TicketManager.ashx接口SQL注入漏洞复现 [附POC] 0x01 前言 …...

设计模式六大原则之:依赖倒置原则
1. 依赖倒置原则简介 依赖倒置原则(Dependency Inversion Principle, DIP) 是面向对象设计的核心原则之一,由罗伯特马丁(Robert C. Martin)提出,旨在降低类间的依赖度,使之更易于维护和扩展。该原则主张高层模块不应该依赖于底层模块&#x…...
06_Linux中如何让程序重启后自动启动
Linux中如何让程序重启后自动启动 systemd单元文件1.创建服务文件!!!服务配置文件的介绍 2.需要配置服务的状态(加载和启用服务)3.验证服务程序的运行状态4.打印程序的标准输出 systemd单元文件 Systemd 是现代 Linux…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...

负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...