99久久全国免费观看_国产一区二区三区四区五区VM_久久www人成免费看片中文_国产高清在线a视频大全_深夜福利www_日韩一级成人av

一口Linux
認(rèn)證:優(yōu)質(zhì)創(chuàng)作者
作者動(dòng)態(tài)
10種初學(xué)者最常見(jiàn)的c語(yǔ)言段錯(cuò)誤實(shí)例及原因分析
1星期前
linux系統(tǒng)監(jiān)控工具小神器:btop
3星期前
有沒(méi)有權(quán)貴開(kāi)后門(mén)讓子女做軟件開(kāi)發(fā)人員?
05-10 23:36
一文包你學(xué)會(huì)網(wǎng)絡(luò)數(shù)據(jù)抓包
03-15 09:26
C語(yǔ)言初學(xué)者編程水平上不來(lái)?不妨嘗試這10個(gè)C語(yǔ)言例子
03-14 20:31

Camera | 10.linux驅(qū)動(dòng) led架構(gòu)-基于rk3568

前面文章我們簡(jiǎn)單給大家介紹了如何移植閃光燈芯片sgm3141,該驅(qū)動(dòng)依賴了led子系統(tǒng)和v4l2子系統(tǒng)。 V4L2可以參考前面camera系列文章,本文主要講述led子系統(tǒng)。

一、LED子系統(tǒng)框架

Linux內(nèi)核的 led 子系統(tǒng)主要功能:

  • 為每個(gè)設(shè)備在/sys/class/leds下創(chuàng)建不同的文件節(jié)點(diǎn),用于操作led
  • 抽象出所有的燈基本操作,設(shè)置亮、滅,光強(qiáng)、閃爍等

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

  • Hardware: 硬件設(shè)備,指的是LED,可以是各種設(shè)備上的led燈

  • 硬件驅(qū)動(dòng)層: 是直接操作硬件的實(shí)現(xiàn),用于驅(qū)動(dòng)硬件,實(shí)現(xiàn)相應(yīng)的功能,并且將硬件設(shè)備注冊(cè)進(jìn)框架之中。

  • 核心層: 將LED進(jìn)行統(tǒng)一管理,向下提供注冊(cè)接口,向上提供統(tǒng)一訪問(wèn)接口,方便用戶訪問(wèn)

  • 用戶層: 用戶通過(guò)指定的文件節(jié)點(diǎn),能夠直接控制LED的亮滅。

不同的led位于不同的外設(shè)上,有的可能通過(guò)gpio控制,也可能由其他的芯片控制, 有的led只需要控制亮滅,有的需要設(shè)置為閃爍,只需要基于架構(gòu)設(shè)置對(duì)應(yīng)的回調(diào)函數(shù)即可。

二、LED子系統(tǒng)驅(qū)動(dòng)文件

了解完LED子系統(tǒng)框架之后,我們來(lái)分析一下其相關(guān)的目錄結(jié)構(gòu)!

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    *【*表示核心文件】

上面即為L(zhǎng)ED子系統(tǒng)的目錄結(jié)構(gòu),其主要核心文件有:

  • led-core.c:核心層實(shí)現(xiàn),抽象軟件實(shí)現(xiàn)的相關(guān)功能,如閃爍,亮度設(shè)置等等,并管理LED設(shè)備
  • led-gpio.c:直接控制硬件設(shè)備,并且將其硬件設(shè)備注冊(cè)進(jìn)入LED驅(qū)動(dòng)框架
  • led-class.c:定義用戶訪問(wèn)的相關(guān)接口
  • led-class-flash.c:燈閃爍相關(guān)功能函數(shù)實(shí)現(xiàn)
  • led-triggers.c:LED出發(fā)功能的抽象
  • ledtrig-cpu.c:將LED作為CPU燈
  • ledtrig-heartbeat.c:將LED作為心跳燈

打開(kāi)了LED子系統(tǒng)目錄下的kernel/drivers/leds/Makefile,我們看到

# SPDX-License-Identifier: GPL-2.0# LED Coreobj-$(CONFIG_NEW_LEDS)+= led-core.oobj-$(CONFIG_LEDS_CLASS)+= led-class.oobj-$(CONFIG_LEDS_CLASS_FLASH)+= led-class-flash.oobj-$(CONFIG_LEDS_TRIGGERS)+= led-triggers.o

我們必須在內(nèi)核的配置中,通過(guò) make menuconfig打開(kāi)LED的相關(guān)配置,才支持LED相關(guān)功能。

三、查看sysfs文件結(jié)構(gòu)

1. sys/class/leds/

我們?cè)陂_(kāi)發(fā)板中輸入ls /sys/class/leds/,可以查看LED子系統(tǒng)生成的文件信息。

rk3568_r:/ # ls /sys/class/ledsblue  gpio-flash  green  mmc0::  red  
  • blue:板子的RGB燈的藍(lán)色
  • green:板子的RGB燈的綠色
  • red: 板子的RGB燈的紅色
  • gpio-flash:camera gpio閃光燈
  • mmc0:: :SD卡指示燈

2. red等子目錄

根據(jù)打開(kāi)配置的不同,生成不同的文件節(jié)點(diǎn),比如red目錄下信息:

rk3568_r:/sys/class/leds # ls redbrightness  max_brightness  red_bri_reg  subsystem  ueventdevice      power           red_delay    trigger

相關(guān)屬性文件有:brightness、max_brightness、trigger等

  1. max_brightness:表示LED燈的最大亮度值。
  2. brightness:表示當(dāng)前LED燈的亮度值,它的可取 值范圍為[0~max_brightness],一些LED設(shè)備不支持多級(jí)亮度,直接以非0值來(lái) 表示LED為點(diǎn)亮狀態(tài),0值表示滅狀態(tài)。
@kernel/include/linux/leds.henum led_brightness { LED_OFF  = 0,    //全暗 LED_HALF = 127,  //一半亮度 LED_FULL = 255,  //最大亮度};
  1. delay_off、delay_on:trigger為timer時(shí),LED亮滅的時(shí)間,單位ms
  2. trigger:則指示了LED燈的觸發(fā)方式,查看該文件的內(nèi)容時(shí),該文件會(huì) 列出它的所有可用觸方式,而當(dāng)前使用的觸發(fā)方式會(huì)以“[]”符號(hào)括起。

常見(jiàn)的觸 發(fā)方式如下表所示:

觸發(fā)方式 說(shuō)明 none 無(wú)觸發(fā)方式 disk-activity 硬盤(pán)活動(dòng) nand-disk nand flash活動(dòng) mtd mtd設(shè)備活動(dòng) timer 定時(shí)器 heartbeat 系統(tǒng)心跳 1)點(diǎn)亮 LED

echo 255 > /sys/class/leds/red/brightnesscat /sys/class/leds/red/brightnesscat /sys/class/leds/red/max_brightness

2)關(guān)閉led

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

3)這幾個(gè)文件節(jié)點(diǎn)由下面宏表示,

@drivers/leds/led-class.cstatic DEVICE_ATTR_RO(max_brightness);#ifdef CONFIG_LEDS_TRIGGERSstatic 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,};#endifstatic 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,};

創(chuàng)建位置:

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 # lsbrightness  flash_strobe   max_brightness     power      triggerdevice      flash_timeout  max_flash_timeout  subsystem  uevent

創(chuàng)建代碼:

@drivers/leds/led-class-flash.cstatic 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,};

注冊(cè)代碼

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); ……}

測(cè)試gpio閃光燈

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

注意,實(shí)際操作攝像頭閃光燈,并不是通過(guò)sysfs下的文件節(jié)點(diǎn)操作,而是通過(guò)v4l2架構(gòu)下發(fā)ioctl的命令來(lái)實(shí)現(xiàn)的

四、驅(qū)動(dòng)解析

1. 結(jié)構(gòu)體和注冊(cè)函數(shù)

下面介紹led相關(guān)的重要的結(jié)構(gòu)體

struct led_classdev { const char  *name; enum led_brightness  brightness;       //光強(qiáng) enum led_brightness  max_brightness;   //最大光強(qiáng) 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);  //設(shè)置光強(qiáng) /*  * 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); //獲取光強(qiáng) /*  * 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;};

該結(jié)構(gòu)體包括led操作的所有信息,和回調(diào)函數(shù)

注冊(cè)struct led_classdev結(jié)構(gòu)圖變量:

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

對(duì)于gpio閃光燈,則需要填充一下結(jié)構(gòu)體:

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閃光燈注冊(cè)函數(shù):

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

2. gpio閃光燈sgm3141驅(qū)動(dòng)詳解

看上圖:

  1. sgm3141驅(qū)動(dòng)通過(guò)函數(shù)led_classdev_flash_register()->led_classdev_register()向led子系統(tǒng)注冊(cè)該設(shè)備
  2. sgm3141驅(qū)動(dòng)通過(guò)函數(shù)v4l2_async_register_subdev()向v4l2子系統(tǒng)注冊(cè)該設(shè)備
  3. 如果用戶直接通過(guò)/sys/class/leds/gpio-flash/flash_strobe文件操作led燈,則會(huì)直接調(diào)用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拍照時(shí)操作閃光燈,則是通過(guò)v4l2子系統(tǒng)調(diào)用下發(fā)ioctl命令 命令序列:
V4L2_CID_FLASH_LED_MODE :設(shè)置led mod為 V4L2_FLASH_LED_MODE_TORCH(2),并點(diǎn)燈V4L2_CID_FLASH_LED_MODE:到達(dá)指定超時(shí)時(shí)間(2.7秒),設(shè)置led mod為 V4L2_FLASH_LED_MODE_NONE 0V4L2_CID_FLASH_LED_MODE:在此設(shè)置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驅(qū)動(dòng)注冊(cè)流程分析 驅(qū)動(dòng)架構(gòu)基于platform總線,platform_driver 結(jié)構(gòu)體如下:
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, },};

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
本篇所含全部資料,點(diǎn)擊此處留下郵箱我會(huì)發(fā)給你
資料明細(xì):一口Linux.pdf
覺(jué)得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 1
收藏 2
關(guān)注 181
成為作者 賺取收益
全部留言
0/200
成為第一個(gè)和作者交流的人吧
主站蜘蛛池模板: 91麻豆精品在线 | 91精品爽啪蜜夜国产在线播放 | 日本欧美一区 | 午夜高清视频 | 国产性生大片免费观看性 | 一区二区三区精品视频免费看 | 亚洲精品一区二区制服 | 97免费人妻在线视频 | 亚洲а∨天堂久久精品2021 | www.久草视频| haoleav.com在线 | 中日黄色一级片 | 亚洲精品久久久中文字幕 | 天天躁日日躁狠狠躁欧美老妇小说 | 久久九九视频 | 国产亚洲精品欧洲在线观看 | 久热精品在线观看 | www.四虎精品| YW尤物AV无码国产在线观看 | 国产av无码专区亚洲avjulia | 最近中文字幕免费mv2019在线 | 国产精品久久久久久久久久了 | 麻豆入口 | 97人妻熟女成人免费视频 | 婷婷影院在线综合免费视频 | 精品一区日韩成人 | 午夜精品一区二区三区三上悠亚 | 97爱视频 | 无限看片的视频高清在线 | 亚洲av无码偷拍在线观看 | 国产精品久久99精品毛片三a | 粉嫩av一区二区三区免费观看 | 大地资源第二页中文高清版 | 国产亚洲一区二区三区四区 | 国产免费一区二区三区在线观看 | 真实国产乱子伦精品视频 | 欧美肥臀大屁股MAGNET | 人妻无码中文字幕永久在线 | 精品国产肉丝袜久久 | 亚洲精品成人悠悠色影视 | 国产精品69精品一区二区三区 |