Camera | 10.linux驱动 led架构-基于rk3568

news2024/11/16 10:26:29

前面文章我们简单给大家介绍了如何移植闪光灯芯片sgm3141,该驱动依赖了led子系统和v4l2子系统。
V4L2可以参考前面camera系列文章,本文主要讲述led子系统。

一、LED子系统框架

Linux内核的 led 子系统主要功能:

  • 为每个设备在/sys/class/leds下创建不同的文件节点,用于操作led
  • 抽象出所有的灯基本操作,设置亮、灭,光强、闪烁等

框架所处的位置,正如上图所示,由下往上看:

  • Hardware:
    硬件设备,指的是LED,可以是各种设备上的led灯

  • 硬件驱动层:
    是直接操作硬件的实现,用于驱动硬件,实现相应的功能,并且将硬件设备注册进框架之中。

  • 核心层:
    将LED进行统一管理,向下提供注册接口,向上提供统一访问接口,方便用户访问

  • 用户层:
    用户通过指定的文件节点,能够直接控制LED的亮灭。

不同的led位于不同的外设上,有的可能通过gpio控制,也可能由其他的芯片控制,
有的led只需要控制亮灭,有的需要设置为闪烁,只需要基于架构设置对应的回调函数即可。

二、LED子系统驱动文件

了解完LED子系统框架之后,我们来分析一下其相关的目录结构!

kernel
│   └── driver
│   │   └── leds
│   │   │   ├──Makefile
│   │   │   ├──led-core.c            *
│   │   │   ├──led-gpio.c
│   │   │   ├──led-class.c           *
│   │   │   ├──led-class-flash.c  *
│   │   │   ├──led-triggers.c       *
│   │   │   ├──......
│   │   │   └── trigger
│   │   │   │   ├── ledtrig-cpu.c
│   │   │   │   ├── ledtrig-heartbeat.c
│   │   │   │   ├── .......
include
│   └── linux
│   │  ├──leds.h    *
【*表示核心文件】

上面即为LED子系统的目录结构,其主要核心文件有:

  • led-core.c:核心层实现,抽象软件实现的相关功能,如闪烁,亮度设置等等,并管理LED设备
  • led-gpio.c:直接控制硬件设备,并且将其硬件设备注册进入LED驱动框架
  • led-class.c:定义用户访问的相关接口
  • led-class-flash.c:灯闪烁相关功能函数实现
  • led-triggers.c:LED出发功能的抽象
  • ledtrig-cpu.c:将LED作为CPU灯
  • ledtrig-heartbeat.c:将LED作为心跳灯

打开了LED子系统目录下的kernel/drivers/leds/Makefile,我们看到


# SPDX-License-Identifier: GPL-2.0

# LED Core
obj-$(CONFIG_NEW_LEDS)+= led-core.o
obj-$(CONFIG_LEDS_CLASS)+= led-class.o
obj-$(CONFIG_LEDS_CLASS_FLASH)+= led-class-flash.o
obj-$(CONFIG_LEDS_TRIGGERS)+= led-triggers.o

我们必须在内核的配置中,通过 make menuconfig打开LED的相关配置,才支持LED相关功能。

三、查看sysfs文件结构

1. sys/class/leds/

我们在开发板中输入ls /sys/class/leds/,可以查看LED子系统生成的文件信息。

rk3568_r:/ # ls /sys/class/leds
blue  gpio-flash  green  mmc0::  red  
  • blue:板子的RGB灯的蓝色
  • green:板子的RGB灯的绿色
  • red: 板子的RGB灯的红色
  • gpio-flash:camera gpio闪光灯
  • mmc0:: :SD卡指示灯

2. red等子目录

根据打开配置的不同,生成不同的文件节点,比如red目录下信息:

rk3568_r:/sys/class/leds # ls red
brightness  max_brightness  red_bri_reg  subsystem  uevent
device      power           red_delay    trigger

相关属性文件有:brightness、max_brightness、trigger等

  1. max_brightness:表示LED灯的最大亮度值。
  2. brightness:表示当前LED灯的亮度值,它的可取 值范围为[0~max_brightness],一些LED设备不支持多级亮度,直接以非0值来 表示LED为点亮状态,0值表示灭状态。
@kernel/include/linux/leds.h
enum led_brightness {
 LED_OFF  = 0,    //全暗
 LED_HALF = 127,  //一半亮度
 LED_FULL = 255,  //最大亮度
};
  1. delay_off、delay_on:trigger为timer时,LED亮灭的时间,单位ms
  2. trigger:则指示了LED灯的触发方式,查看该文件的内容时,该文件会 列出它的所有可用触方式,而当前使用的触发方式会以“[]”符号括起。

常见的触 发方式如下表所示:

触发方式说明
none无触发方式
disk-activity硬盘活动
nand-disknand flash活动
mtdmtd设备活动
timer定时器
heartbeat系统心跳

1)点亮 LED

echo 255 > /sys/class/leds/red/brightness
cat /sys/class/leds/red/brightness
cat /sys/class/leds/red/max_brightness

2)关闭led

echo 0 > /sys/class/leds/red/delay_on
或
echo 0 > /sys/class/leds/red/brightness

3)这几个文件节点由下面宏表示,

@drivers/leds/led-class.c
static DEVICE_ATTR_RO(max_brightness);

#ifdef CONFIG_LEDS_TRIGGERS
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
static struct attribute *led_trigger_attrs[] = {
	&dev_attr_trigger.attr,
	NULL,
};
static const struct attribute_group led_trigger_group = {
	.attrs = led_trigger_attrs,
};
#endif

static struct attribute *led_class_attrs[] = {
	&dev_attr_brightness.attr,
	&dev_attr_max_brightness.attr,
	NULL,
};

static const struct attribute_group led_group = {
	.attrs = led_class_attrs,
};

static const struct attribute_group *led_groups[] = {
	&led_group,
#ifdef CONFIG_LEDS_TRIGGERS
	&led_trigger_group,
#endif
	NULL,
};

创建位置:

int of_led_classdev_register(struct device *parent, struct device_node *np,
			    struct led_classdev *led_cdev)
{
	……
	led_cdev->dev = device_create_with_groups(leds_class, parent, 0,
				led_cdev, led_cdev->groups, "%s", name);
    ……
}

3. gpio-flash闪光灯目录

rk3568_r:/sys/class/leds/gpio-flash # ls
brightness  flash_strobe   max_brightness     power      trigger
device      flash_timeout  max_flash_timeout  subsystem  uevent

创建代码:

@drivers/leds/led-class-flash.c
static struct attribute *led_flash_strobe_attrs[] = {
	&dev_attr_flash_strobe.attr,
	NULL,
};

static struct attribute *led_flash_timeout_attrs[] = {
	&dev_attr_flash_timeout.attr,
	&dev_attr_max_flash_timeout.attr,
	NULL,
};

static struct attribute *led_flash_brightness_attrs[] = {
	&dev_attr_flash_brightness.attr,
	&dev_attr_max_flash_brightness.attr,
	NULL,
};

static struct attribute *led_flash_fault_attrs[] = {
	&dev_attr_flash_fault.attr,
	NULL,
};

static const struct attribute_group led_flash_strobe_group = {
	.attrs = led_flash_strobe_attrs,
};

static const struct attribute_group led_flash_timeout_group = {
	.attrs = led_flash_timeout_attrs,
};

static const struct attribute_group led_flash_brightness_group = {
	.attrs = led_flash_brightness_attrs,
};

static const struct attribute_group led_flash_fault_group = {
	.attrs = led_flash_fault_attrs,
};

注册代码

int led_classdev_flash_register(struct device *parent,
				struct led_classdev_flash *fled_cdev)
{
	……
	if (led_cdev->flags & LED_DEV_CAP_FLASH) {
		……
		/* Select the sysfs attributes to be created for the device */
		led_flash_init_sysfs_groups(fled_cdev);
	}

	/* Register led class device */
	ret = led_classdev_register(parent, led_cdev);
	……
}

测试gpio闪光灯

echo 1 > /sys/class/leds/gpio-flash/flash_strobe  

注意,实际操作摄像头闪光灯,并不是通过sysfs下的文件节点操作,而是通过v4l2架构下发ioctl的命令来实现的

四、驱动解析

1. 结构体和注册函数

下面介绍led相关的重要的结构体

struct led_classdev {
	const char		*name;
	enum led_brightness	 brightness;       //光强
	enum led_brightness	 max_brightness;   //最大光强
	int			 flags;
	…………

	/* set_brightness_work / blink_timer flags, atomic, private. */
	unsigned long		work_flags;
     …………	
	/* Set LED brightness level
	 * Must not sleep. Use brightness_set_blocking for drivers
	 * that can sleep while setting brightness.
	 */
	void		(*brightness_set)(struct led_classdev *led_cdev,
					  enum led_brightness brightness);  //设置光强
	/*
	 * Set LED brightness level immediately - it can block the caller for
	 * the time required for accessing a LED device register.
	 */
	int (*brightness_set_blocking)(struct led_classdev *led_cdev,
				       enum led_brightness brightness);
	/* Get LED brightness level */
	enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); //获取光强

	/*
	 * Activate hardware accelerated blink, delays are in milliseconds
	 * and if both are zero then a sensible default should be chosen.
	 * The call should adjust the timings in that case and if it can't
	 * match the values specified exactly.
	 * Deactivate blinking again when the brightness is set to LED_OFF
	 * via the brightness_set() callback.
	 */
	int		(*blink_set)(struct led_classdev *led_cdev,
				     unsigned long *delay_on,
				     unsigned long *delay_off);

	struct device		*dev;
	const struct attribute_group	**groups;

	struct list_head	 node;			/* LED Device list */
	const char		*default_trigger;	/* Trigger to use */

	unsigned long		 blink_delay_on, blink_delay_off;
	struct timer_list	 blink_timer;
	int			 blink_brightness;
	int			 new_blink_brightness;
	void			(*flash_resume)(struct led_classdev *led_cdev);

	struct work_struct	set_brightness_work;
	int			delayed_set_value;

#ifdef CONFIG_LEDS_TRIGGERS
	/* Protects the trigger data below */
	struct rw_semaphore	 trigger_lock;

	struct led_trigger	*trigger;
	struct list_head	 trig_list;
	void			*trigger_data;
	/* true if activated - deactivate routine uses it to do cleanup */
	bool			activated;
#endif

#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
	int			 brightness_hw_changed;
	struct kernfs_node	*brightness_hw_changed_kn;
#endif

	/* Ensures consistent access to the LED Flash Class device */
	struct mutex		led_access;
};

该结构体包括led操作的所有信息,和回调函数

注册struct led_classdev结构图变量:

#define led_classdev_register(parent, led_cdev)				\
	of_led_classdev_register(parent, NULL, led_cdev)

对于gpio闪光灯,则需要填充一下结构体:

struct led_classdev_flash {
	/* led class device */
	struct led_classdev led_cdev;

	/* flash led specific ops */
	const struct led_flash_ops *ops;

	/* flash brightness value in microamperes along with its constraints */
	struct led_flash_setting brightness;

	/* flash timeout value in microseconds along with its constraints */
	struct led_flash_setting timeout;

	/* LED Flash class sysfs groups */
	const struct attribute_group *sysfs_groups[LED_FLASH_SYSFS_GROUPS_SIZE];
};

gpio闪光灯注册函数:

int led_classdev_flash_register(struct device *parent,
				struct led_classdev_flash *fled_cdev)

2. gpio闪光灯sgm3141驱动详解


看上图:

  1. sgm3141驱动通过函数led_classdev_flash_register()->led_classdev_register()向led子系统注册该设备
  2. sgm3141驱动通过函数v4l2_async_register_subdev()向v4l2子系统注册该设备
  3. 如果用户直接通过/sys/class/leds/gpio-flash/flash_strobe文件操作led灯,则会直接调用struct led_flash_ops flash_ops的 .strobe_set方法,即sgm3141_led_flash_strobe_set()

操作log:

[  492.026391] sgm3141_led_flash_strobe_set+0x24/0x78                                          
[  492.026453] flash_strobe_store+0x88/0xd8                                                    
[  492.026517] dev_attr_store+0x18/0x28                                                        
[  492.026571] sysfs_kf_write+0x48/0x58                                                        
[  492.026620] kernfs_fop_write+0xf4/0x220                                                     
[  492.026683] __vfs_write+0x34/0x158                                                          
[  492.026733] vfs_write+0xb0/0x1d0                                                            
[  492.026784] ksys_write+0x64/0xe0                                                            
[  492.026833] __arm64_sys_write+0x14/0x20                                                     
[  492.026867] el0_svc_common.constprop.0+0x64/0x178                                           
[  492.026912] el0_svc_handler+0x28/0x78                                                       
[  492.026966] el0_svc+0x8/0xc 
  1. 如果用户的app拍照时操作闪光灯,则是通过v4l2子系统调用下发ioctl命令
    命令序列:
V4L2_CID_FLASH_LED_MODE :设置led mod为 V4L2_FLASH_LED_MODE_TORCH(2),并点灯
V4L2_CID_FLASH_LED_MODE:到达指定超时时间(2.7秒),设置led mod为 V4L2_FLASH_LED_MODE_NONE 0
V4L2_CID_FLASH_LED_MODE:在此设置led mod为V4L2_FLASH_LED_MODE_FLASH(1)
V4L2_CID_FLASH_STROBE_STOP:停止闪光

操作log:

[   90.246203] sgm3141 V4L2_CID_FLASH_LED_MODE 2
[   90.246251] sgm3141_set_ctrl(),376
[   90.246262] sgm3141_set_output(),78 0
[   90.246277] sgm3141_set_output(),78 1

[   92.902746] sgm3141 V4L2_CID_FLASH_LED_MODE 0
[   92.902775] sgm3141_set_ctrl(),376
[   92.902781] sgm3141_set_output(),78 0

[   93.034903] sgm3141 V4L2_CID_FLASH_LED_MODE 1
[   93.034929] sgm3141_set_ctrl(),376
[   93.034934] sgm3141_set_output(),78 0
[   93.034943] sgm3141_led_flash_strobe_set(),166 state=1
[   93.034959] sgm3141_set_output(),78 1

[   93.034977] sgm3141 V4L2_CID_FLASH_STROBE_STOP 1
[   93.034988] sgm3141_set_ctrl(),406
[   93.034993] sgm3141_led_flash_strobe_set(),166 state=0
[   93.035002] sgm3141_set_output(),78 0
[   93.035058] sgm3141_timeout_work(),117
  1. sgm驱动注册流程分析
    驱动架构基于platform总线,platform_driver 结构体如下:
static const struct of_device_id sgm3141_led_dt_match[] = {
	{ .compatible = "sgmicro,sgm3141" },
	{},
};
MODULE_DEVICE_TABLE(of, sgm3141_led_dt_match);

static struct platform_driver sgm3141_led_driver = {
	.probe		= sgm3141_led_probe,
	.remove		= sgm3141_led_remove,
	.driver		= {
		.name	= "sgm3141-flash",
		.of_match_table = sgm3141_led_dt_match,
	},
};

点击下面图标,
扫描二维码,关注一口君
学习嵌入式、驱动、Linux

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/594758.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Linux内核源码分析》(2)进程原理及系统调用

《Linux内核源码分析》(2)进程原理及系统调用 一、进程 操作系统的作用:作为硬件的使用层,提供使用硬件资源的能力, 进程的作用:作为操作系统使用层,提供使用操作系统抽象出的资源层的能力 进程、线程和程序的区别&…

【计算机视觉】Segment Anything 安装配置及代码测试(含源代码)

文章目录 一、前言二、安装2.1 基本要求2.2 Install Segment Anything 三、代码使用示例3.1 Automatically generating object masks with SAM3.2 Environment Set-up3.3 显示标注3.4 图像示例3.5 Automatic mask generation3.6 Automatic mask generation options 一、前言 目…

客户体验:响应速度是他们的 No.1 Pick么?

服务响应速度在为消费者提供服务时极为重要,那么,在消费者整体体验中,响应速度是否是消费者最在意的呢? 无论是对企业还是消费者来说,时间都至关重要。消费者在寻求客户服务时,不喜欢等待。根据《客户服务受…

【Python asyncio】零基础也能轻松掌握的学习路线与参考资料

Python asyncio是一个强大而易于使用的库,让Python程序员能够编写高效的异步IO应用程序。它为程序员提供了一种简单而优雅的方法来避免使用 Python GIL(全局解释器锁),同时允许他们轻松地处理高并发的网络通信和并发任务执行。下面…

蓝桥杯数论总结:快速幂和矩阵快速幂

本文先是给出快速幂的原理,又由一道例题明确快速幂的Python代码模版;而后给出矩阵快速幂的原理(介绍了矩阵相乘,对没学过线代者友好),和矩阵快速幂的模版。再给出快速幂和矩阵快速幂相关的题单。 目录 快…

Linux高级---k8s存储

文章目录 一、数据卷的概述二、关系图三、数据卷的类型1、emptydira、描述b、适用场景c、emptydir应用 2、hostpatha、描述b、适用场景c、hostpath应用 3、nfsa、描述b、适用场景c、nfs应用 4、PV和PVCa、描述b、存储卷和存储卷声明的关系c、存储卷声明的管理过程 5、PVa、资源…

10个可以快速用Python进行数据分析的小技巧

一些小提示和小技巧可能是非常有用的,特别是在编程领域。有时候使用一点点黑客技术,既可以节省时间,还可能挽救“生命”。 一个小小的快捷方式或附加组件有时真是天赐之物,并且可以成为真正的生产力助推器。所以,这里…

基于Spring Boot+Vue的课堂管理系统

介绍 基于Spring BootVue的课堂管理系统。前后端分离。包含教师授课管理、学生选退课、聊天室、签到、笔记管理模块等。 技术架构 spring BootMyBatisRedisWebSocketVueCLIAxiosElement UI 项目特点: - 后台使用MyBatis连接数据库,编写后台服务器的…

【教程】2步白嫖使用DeepL Pro会员版 [附插件]

转载请注明出处:小锋学长生活大爆炸[xfxuezhang.cn] 【教程】5步白嫖使用Grammarly Premium高级版 [附脚本] 适用说明 Edge、Chrome等,使用了Chrome内核的浏览器应该都可以吧。 开始白嫖 1、下载并解压插件,下载链接:https://x…

第2章:数据结构【AcWing】

文章目录 单链表定义初始化头插在下标为pos位置后插入删除下标为pos后的结点遍历 双链表定义初始化在下标为pos后插入删除下标为pos的位置 栈和队列栈定义示例代码 队列定义示例代码循环队列定义示例代码 单调栈和单调队列单调栈朴素方法 O ( n 2 ) O(n^2) O(n2)优化 O ( n ) …

Web的基本漏洞--逻辑漏洞

目录 一、逻辑漏洞介绍 1.逻辑漏洞的原理 2.逻辑漏洞的分类 3.常见的逻辑漏洞 4.挖掘逻辑漏洞 一、逻辑漏洞介绍 1.逻辑漏洞的原理 逻辑漏洞是指由于程序逻辑不严或逻辑太复杂,导致一些逻辑分支不能够正常处理或处理错误,从而进行攻击。一般出现任…

英国皇家植物园采用机器学习预测植物抗疟性,将准确率从 0.46 提升至 0.67

内容一览:疟疾是严重危害人类生命健康的重大传染病,研究人员一直在致力于寻找新的植物源性抗疟疾化合物,以研发相关药物。近期英国皇家植物园利用机器学习 算法 有效预测了植物抗疟性,该研究成果目前已发表在《Frontiers in Plant…

路径规划算法:基于风驱动优化的路径规划算法- 附代码

路径规划算法:基于风驱动优化的路径规划算法- 附代码 文章目录 路径规划算法:基于风驱动优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化算法…

游戏场景的转换——状态模式

状态模式 游戏比较复杂时,通常会设计成多个场景。 切换场景的好处 1、重复使用场景 跳转切换场景的代码有两种一种是旧版的方法 Application.LoadLevel(“SampleScene”);另一种是新版的方法 SceneManager.LoadScene(“SampleScene”); 例子1:通过场景…

通过IEDA连接Linux上的MYSQL

一、打开idea新建项目 idea与数据库的连接是与项目强相关的 在项目A中配置的数据库连接a,那么只能在项目A中能看到和使用数据库连接a 二、配置新的数据库连接 1.点击界面左侧栏中的Database,唤出数据库连接界面 2. 新建数据库(mysql&#x…

Linux:apache配置与应用

Linux:apache配置与应用 一、虚拟 Web 主机1.1 虚拟Web主机1.2 httpd服务支持的虚拟主机类型 二、基于域名的虚拟主机2.1 为虚拟主机提供域名解析2.2 为虚拟主机准备网页文档2.3 添加虚拟主机配置2.4 设置访问控制2.5 加载独立的配置文件2.6 在客户机中访问虚拟 Web…

RabbitMQ消息属性详解

content-type属性 如同各种标准化的HTTP规范,content-type传输消息体的MIME类型。例如,如果你的应用程序正在发送JSON序列化的数据值,那么将content-type属性设置为application/json将允许尚待开发的消费者应用程序在收到消息时检查消息类型…

BiFormer实战:使用BiFormer实现图像分类任务(一)

文章目录 摘要安装包安装timm安装 grad-cam 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集 摘要 论文翻译:https://wanghao.blog.csdn.net/article/details/130186102 官方源码:https://github.com/rayleizhu/BiFormer BiFormer是今年提出…

java idea常用的快捷方式

文章目录 java idea常用的快捷方式快速复制选多行改变代码格式化 快速代码编辑psvmsout5.for java idea常用的快捷方式 快速复制 c t r l d \color{red}{ctrld} ctrld 选多行改变 A l t 鼠标 \color{red}{Alt鼠标} Alt鼠标 代码格式化 C t r l A l t l \color{red}{Ctrl…

Web的基本漏洞--代码执行漏洞

目录 一、代码执行漏洞的介绍 1.代码执行漏洞的原理 2.常用含有的代码执行漏洞的函数 3.代码执行漏洞的危害 4.代码执行漏洞的防范措施 一、代码执行漏洞的介绍 1.代码执行漏洞的原理 web应用程序是指程序员在代码中使用了一些执行函数例如php的eval,assert等…