ptz 发布的文章

增加时间戳

app/build.gradleandroid 闭包之外增加:

def generateTime() {
    return new Date().format("yyyy_MM_dd_HH_mm_ss")
}

增加文件名

app/build.gradleandroid 包中增加:

android {
    defaultConfig {
        ...
    }

    // 自定义打包名称
    android.applicationVariants.all { variant ->
        variant.outputs.all {
            outputFileName = "${applicationId}_${buildType.name}_v${versionName}_${generateTime()}.apk"
        }
    }

    buildTypes {
        ...
    }

版本号

源码里面如果需要用到app/build.gradle的版本号,可以使用下面这个:

public static final String VERSION = BuildConfig.VERSION_NAME;

参考:

Android Studio 打包APK(详细版)
https://blog.csdn.net/qq_38436214/article/details/112288954

sqlite 数据库设计超过容量就删除最前面的 n 行数据,用到的 sql 语句如下:

    public void deleteTableHead(SQLiteDatabase db,
                                String table, String column, long num) {
        String delete = "delete from " + table + " where " + column +
                " in(select " + column + " from " + table + " limit " + num + ")";
        db.execSQL(delete);
    }

参考:

删除SQLITE数据库前N行或指定行问题
https://www.cnblogs.com/elect-fans/archive/2012/08/04/2622480.html
Sqlite数据库添加,删除前n条记录
https://blog.csdn.net/asdssaaaa/article/details/52229546
安卓 SQLite 数据库删除前 n 条记录
https://blog.csdn.net/fzhhsa/article/details/103032844?spm=1001.2101.3001.6650.8&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-8.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-8.pc_relevant_default&utm_relevant_index=12
Sqlite之删除超过50条的数据
https://blog.csdn.net/u014213012/article/details/76269768

android 需要显示实时时间,可以使用 google 提供好的 TextClock

xml

<TextClock
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:format12Hour="yyyy-MM-dd  EEEE  aa  HH:mm:ss"
        android:format24Hour="yyyy-MM-dd  EEEE  aa  HH:mm:ss" />

格式

格式 效果
yyyy年MM月dd日 2020年11月17日
yyyy/MM/dd 2020/11/17
yyyy-MM-dd 2020-11-17
EEEE 星期二
EEE 周二
aa 下午
HH:mm:ss 15:53:05
hh:mm:ss 03:53:05

参考:

Android控件之TextClock
https://blog.csdn.net/u011153817/article/details/52838330
Android TextClock时间格式
https://www.jianshu.com/p/e6ab75502174

转自: https://shimo.im/docs/3RTDdGjQdTtjtPKj/read

本文是广和通的分包方法。

文档说明

本文档以SC826(MSM8953平台,Android 7)为例,描述如何对SOC镜像文件分包。

应用背景

客户用QFIL刷固件的时候,由于客户自己编译生成的固件是没有经过分包的,烧录耗时较久。如果将编译生成的固件先分包后,再烧录就可以提升烧录效率。

- 阅读剩余部分 -

转自: http://cache.baiducontent.com/c?m=n2F9tWNTq3bABpgqBR7Rrnq7eJEBV0b-CYkrdH_ovC7GbC2ir5dWTxjAm4AY0et-bhlTXLonho7jd4FkJf_vKSDR5O3CN4gb4ortWKt2smBJDHXviGRdKNAjHyFI5BQr&p=8d79dc16d9c15fed08e2977f0b5182&newp=8b2a970f86cc42ae5ef6cf211c7a8d231610db2151d6d1126b82c825d7331b001c3bbfb422201104d3c5786103a94a59e9f03171330923a3dda5c91d9fb4c57479c2&s=c4ca4238a0b92382&user=baidu&fm=sc&query=devcfg%2Embn&qid=918dfdf200012565&p1=4

L1

abl.img

aop.img

bluetooth.img

boot.img

cmnlib.img

cmnlib64.img

devcfg.img

dsp.img

dtbo.img

fw_4j1ed.img

fw_4u1ea.img

hyp.img

keymaster.img

LOGO.img

ls.txt

modem.img

oem_stanvbk.img

qupfw.img

storsec.img

system.img

tz.img

vbmeta.img

vendor.img

xbl.img

xbl_config.img

L2

boot:boot 分区包含通过 m****ootimg 组合在一起的内核映像和 RAM 磁盘。为了直接刷写内核而不刷写新的 boot 分区,可以使用虚拟分区:

kernel:kernel 虚拟分区仅覆盖内核(zImage、zImage-dtb、Image.gz-dtb),方法是写入新的映像来覆盖旧的映像。为此,它会确定 eMMC 中现有内核映像的起始位置并将新内核映像复制到该位置。请记住,新内核映像可能会大于现有内核映像。引导加载程序可以通过移动其后的任何数据来腾出空间或放弃出错的操作。如果提供的开发内核不兼容,则可能需要使用相关的内核模块更新 dtb 分区(如果存在)、vendor 分区或 system 分区。

ramdisk:ramdisk 虚拟分区通过将新映像写入旧磁盘来仅覆盖 RAM 磁盘。为此,它会确定 eMMC 中现有 ramdisk.img 的起始位置并将新 RAM 磁盘映像复制到该位置。请记住,新 RAM 磁盘映像可能会大于现有 RAM 磁盘映像。引导加载程序可以通过移动其后的任何数据来腾出空间或放弃出错的操作。

system:system 分区主要包含 Android 框架。

recovery:recovery 分区用于存储在 OTA 过程中启动的恢复映像。如果设备支持 A/B 更新,则恢复映像可以是启动映像中包含的 RAM 磁盘,而不是单独的映像。

cache:cache 分区用于存储临时数据,如果设备使用 A/B 更新,则可以不要此分区。cache 分区不需要可从引导加载程序写入,而只需要可清空。大小取决于设备类型和 userdata 分区的可用空间。目前,50MB 至 100MB 应该没问题。

misc:misc 分区供恢复映像使用,存储空间不能小于 4****。

userdata:userdata 分区包含用户安装的应用和数据,包括自定义数据。

metadata:如果设备被加密,则需要使用 metadata 分区,该分区的存储空间不能小于 16MB。

vendor:vendor 分区包含所有不可分发给 Android 开源项目 (AOSP) 的二进制文件。如果没有专有信息,则可以省略此分区。

radio:radio 分区包含无线装置映像。只有包含无线装置且在专用分区中包含无线装置专用软件的设备才需要此分区。

tos:tos 分区用于存储 Trusty 操作系统的二进制映像文件,仅在设备包含 Trusty 时使用。

L3

sbl1.mbn

烧录命令:fastboot flash sbl1 sbl1.bin

作用:second bootloader1的缩写,是在little kernel(lk)前启动,起到引导lk的作用,如果将该分区擦除,则设备表现为进入紧急下载模式,即,擦除该分区后,插入USB显示QDload端口。

rpm.mbn

烧录命令:fastboot flash rpm rpm.mbn

作用:电源管理器,是高通MSM平台另外加的一块芯片,虽然与AP芯片打包在一起,但其是一个独立的ARM Core。之所以加这个东西,就是要控制整个电源相关的sharedresources,比如ldo,clock。负责与SMP,MPM交互进入睡眠或者唤醒整个系统。

adspso.bin

烧录命令:fastboot flash dsp adspso.bin

作用:Partition for adsp dymanic loaders image

tz.mbn

烧录命令:fastboot flash tz tz.mbn

作用:是ARM TrustZone® 技术是系统范围的安全方法,基于安全需求和引导模式配置XPU,NAND MPU

cmnlib(_30).mbn 括号中的内容可能有,可能没

烧录命令:fastboot flash cmnlib cmnlib_30.mbn

作用: Verified boot feature introduced in M needLK to load cmnlib corresponding partitions

km4.mbn

烧录命令:fastboot flash keymaster km4.mbn

作用:Verified boot feature introduced in M needs LK to load keymaster from corresponding partitions

devcfg.mbn

烧录命令:fastboot flash devcfg devcfg.mbn

作用:Partition needed by TZ for M upgrade

NON-HLOS.bin

烧录命令:fastboot flash modem NON-HLOS.bin

作用:modem image,是负责处理通讯协议相关的基带镜像

emmc_appsboot.mbn

烧录命令:fastboot flash aboot emmc_appsboot.mbn

作用:应用程序启动加载程序的分区

boot.img

烧录命令:fastboot flash boot boot.img

作用:由文件头(2k/4k)+kernel+ramdisk.img(根文件统)+dt.img(devicetree)组成,其中kernel对应于out\target\product\msm8909\obj\KERNEL_OBJ\arch\arm\boot下的zImage文件,和out\target\product\msm8909\kernel是同一个文件,只是被重新命名了,通过file zImage,可知zImage:Linux kernel ARM bootexecutable zImage(little-endian)

system.img

烧录命令:fastboot flash -S 256M system system.img(由于system.img太大,故用-S分段发送)

作用:android系统镜像文件

vendor.img

烧录命令: fastboot flash vendor vendor.img

作用:一般存放的是平台,第三方,非google的库,配置,app等文件

splash.img

烧录命令:fastboot flash splash splash.img

作用:开机动画

userdata.img

烧录命令:fastboot flash userdata userdata.img

作用:用户数据

L4

Label Purpose of this partition

Modem Partition for modem

Fsc Cookie partition to store Modem File System’s cookies.

Ssd Partition for ssd diag module. stores the encrypted RSA keys

sbl1 Partition for secondary boot loader

sbl1bak Back up Partition for secondary boot loader

Rpm Partition for rpm image

Rpmbak Back up Partition for rpm image

Tz Partition for tz image

tzbak Back up Partition for tz image

Hyp Partition for hypervisor image

hypbak Back up Partition for hypervisor image

DSP Partition for adsp dymanIC loaders image

modemst1 Copy of Modem File System (Encrypted)

modemst2 Copy of Modem File System (Encrypted)

DDR Partition for DDR.

Fsg Golden copy or backup of Modem File System (Encrypted). Also used to pre-populate the file system.

Sec Sec.dat contains fuse settings, mainly for secure boot and oem setting

splash The splash screen is displayed during the apps bootloader (also called the LK). The display driver in LK will read the splash image data from a separate eMMC partition named

            as ’splash’

aboot Partition for apps boot loader

abootbak Back up Partition for apps boot loader

boot This is the boot partition of your Android device,It includes the android kernel and the ramdisk.

recovery This is specially designed for backup. The recovery partition can be considered as an alternative boot partition

devinfo Device information including:iis_unlocked, is_tampered, is_verified, charger_screen_enabled, display_panel, bootloader_version, radio_version

           All these attirbutes are set based on some specific conditions and written on devinfo partition,.

system This partition contains the entire Android OS, other than the kernel and the ramdisk. This includes the Android GUI and all the system applications that come

           pre-installed on the device

cache This is the partition where Android stores frequently accessed data and app components

persist Partition entry for persist image. which contains data which shouldn’t be changed after the device shipped, for example: calibration data of chips(WIFI, bt, camera, etc.),

           certificates and other security related files. 

misc This partition contains miscellaneous system settings in form of on/off switches. These settings may include CID (Carrier or Region ID), USB configuration and

           certain hardware settings etc

keystore Partition for keystore service.

config Partition needed during display panel initialization. More info at Display_panel_configuration_in_Device_Tree

oem "It is meant for storing OEM specific info. Customer in this case can decide whether he wants to keep this partition or not typically reserved partitions are kept for future use

limits Partition to store LMh params on 8976 target. LMh (Limits management) driver in SBL writes the LMh HW trimmed data into separate partition

          and uses the same data for later reboots

mota Backup partition for M ota upgrade

devcfg Partition needed by TZ for M upgrades.

Dip Partition needed for SafeSwitch, feature (FR26255) designed to allow OEMs and carriers to address new smartphone theft bill issues.

mdtp Partition needed for SafeSwitch, feature (FR26255) designed to allow OEMs and carriers to address new smartphone theft bill issues.

userdata Partition for userdata image

cmnlib Verified boot feature introduced in M needLK to load cmnlib corresponding partitions

keymaster Verified boot feature introduced in M needs LK to load keymaster from corresponding partitions

syscfg Syscfg is internal testing for Vmin and CPR characterization

mcfg All MBNs place holder in flash. Specific MBN would be loaded by mcfg image based on the SIM/Carrier.

msadp used for modem debug policy

apdp used for persisting the debug policy. "Debug policy" is used to better support development and debug on secure/fuse-blown devices One instance of the debug policy

           will be signed for the AP

dpo This partition will store a policy override

比较好用的画线库就是 MPAndroidChart

具体的资料可以参考: MPAndroidChart使用详解
https://blog.csdn.net/dapangzao/article/details/74949541
MPAndroidChart 之LineChart(1)
https://blog.csdn.net/u014769864/article/details/71479591
一步一步教你写股票走势图——分时图一(概述)
https://blog.csdn.net/qqyanjiang/article/details/51442120
在项目中使用MPAndroidChart遇到的问题
https://blog.csdn.net/maxwell0401/article/details/51451816

sg 滤波器: Savitsky Golay filter

github 上面可用的库有两个:

资料

使用问题

  • savitzky-golay-filter 这个需要配套的是 math v2.2
  • jDSP 需要需改 gradle 文件,否则会报错。

参考:

Savitsky-Golay滤波器及源码实现
https://blog.csdn.net/lovelyaiq/article/details/88681499
Savitzky-Golay 滤波器
https://blog.csdn.net/liyuanbhu/article/details/9094945

转自: https://www.jianshu.com/p/f160209bd64b

内核相关文档

Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
Documentation\gpio\gpio.txt
Documentation\devicetree\bindings\gpio\gpio.txt

背景

随着内核的发展,linux驱动框架在不断的变化。在早期,GPIO子系统存在之前,我们驱动需要在代码中配置寄存器来使用GPIO引脚。

此后,出现了gpio子系统,后来又出现了pinctrl子系统。

有些平台的实现没有使用内核提供的pinctrl子系统,而是继续采用在内核提供pinctrl子系统前自己实现的那套机制来pinmux操作,如Ti的omap平台;

有些平台则基于pinctrl子系统来实现pinmux、pinconf的控制。

介绍

GPIO子系统可以说是Linux中最简单的子系统。

  • GPIO(General Purpose Input Output):负责管理整个系统各gpio输入输出管脚的使用情况,同时通过sys文件系统导出了调试信息和应用层控制接口。
  • Pinctrl(Pin Control):负责管理SOC中各pin的状态,比如输出电流能力、是否有内部上拉或者下拉,是否有功能复用等参数。

要想操作GPIO引脚,需要先把所用引脚配置成GPIO功能,这个通过pinctrl子系统来实现。然后可以根据设置的引脚的方向来读取引脚的值和设置输出值。

在BSP工程师实现好GPIO子系统后,我们就可以在设备树中指定GPIO引脚,在驱动中使用GPIO子系统的标准函数来获取GPIO、设置GPIO方向、读取/设置GPIO的值。这样的驱动代码是于单板无关的。

gpio子系统

gpio子系统内部实现主要提供了两类接口:

  • 一类给bsp工程师,用于注册gpio chip(也就是所谓的gpio控制器驱动)
  • 另一部分给驱动工程师使用,为驱动工程师屏蔽了不同gpio chip之间的区别,驱动工程师调用的api的最终操作流程会导向gpio对应的gpio chip的控制代码,也就是bsp的代码。

核心实现

gpio子系统的实现源码在drivers/gpio文件夹下,主要文件有:

在安卓系统中,实现源码在kernel/drivers/gpio

文件 作用
devres.c 针对gpio api增加的devres机制的支持
gpiolib.c gpio子系统的核心实现
gpiolib-of.c 对设备树的支持
gpiolib-acpi.c 和acpi相关,不分析
gpio-xxx.c 根据平台的不同,所对应的gpio控制

gpio子系统提供了两层接口,一层给上层驱动工程师调用,一层给下层bsp工程师调用。

上层使用前,当然先得bsp工程师完成对应的动作。

- 阅读剩余部分 -

转自: https://blog.csdn.net/qq_28992301/article/details/53321610

设备树详解

在Linux3.x版本后,arch/arm/plat-xxx和arch/arm/mach-xxx中,描述板级细节的代码(比如platform_device、i2c_board_info等)被大量取消,取而代之的是设备树,其目录位于arch/arm/boot/dts

1.设备树的组成

1个dts文件+n个dtsi文件,它们编译而成的dtb文件就是真正的设备树

  • soc厂商会把soc公共的特性和多块开发板公用的特性提炼为dtsi,而dts则负责描述某个具体的产品(开发板)的特性。dts直接或间接的包含多个dtsi(类似于c语言的头文件),就体现了一个完整的产品(开发板)所有的特性。以solidrun公司的hummingboard为例,其组成为
imx6dl-hummingboard.dts
        |_imx6dl.dtsi
        |   |_imx6qdl.dtsi
        |_imx6qdl-microsom.dtsi
        |_imx6qdl-microsom-ar8035.dtsi
  • 此外,dts/dtsi兼容c语言的一些语法,能使用宏定义,也能包含.h文件

2.设备树的结构

下面分别是是imx6dl-hummingboard.dts以及imx6dl.dtsi文件,我们以它们为例来分析,不难发现dts文件内容很少,只有一些板级的特征,大部分公共的硬件描述都在dtsi文件中

  • imx6dl-hummingboard.dts 文件节选
/dts-v1/;
#include "imx6dl.dtsi"
#include "imx6qdl-microsom.dtsi"
#include "imx6qdl-microsom-ar8035.dtsi"

/ {
    model = "SolidRun HummingBoard DL/Solo";
    compatible = "solidrun,hummingboard", "fsl,imx6dl";

    ir_recv: ir-receiver {
        compatible = "gpio-ir-receiver";
        gpios = <&gpio1 2 1>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_hummingboard_gpio1_2>;
    };

    regulators {
        compatible = "simple-bus";

        reg_3p3v: 3p3v {
            compatible = "regulator-fixed";
            regulator-name = "3P3V";
            regulator-min-microvolt = <3300000>;
            regulator-max-microvolt = <3300000>;
            regulator-always-on;
        };
    }

&i2c1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_hummingboard_i2c1>;

    rtc: pcf8523@68 {
        compatible = "nxp,pcf8523";
        reg = <0x68>;
    };
};
  • imx6dl.dtsi文件节选
/ {
    aliases {

    /*省略无关代码*/
    }
    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        interrupt-parent = <&intc>;
        ranges;

        /*省略无关代码*/

        timer@00a00600 {
            compatible = "arm,cortex-a9-twd-timer";
            reg = <0x00a00600 0x20>;
            interrupts = <1 13 0xf01>;
            clocks = <&clks IMX6QDL_CLK_TWD>;
        };

        aips-bus@02000000 { /* AIPS1 */
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02000000 0x100000>;
            ranges;

            /*省略无关代码*/      

            gpio1: gpio@0209c000 {
                compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio";
                reg = <0x0209c000 0x4000>;
                interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>,
                         <0 67 IRQ_TYPE_LEVEL_HIGH>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
                #interrupt-cells = <2>;
            };

            /*省略无关代码*/  

            i2c1: i2c@021a0000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";
                reg = <0x021a0000 0x4000>;
                interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&clks IMX6QDL_CLK_I2C1>;
                status = "disabled";
            };

        };
            /*省略无关代码*/  
    };  
};
基本构造
  • {}包围起来的结构称之为节点,dts中最开头的/ {},称为根节点。节点的标准结构是xxx@yyy{…},xxx是节点的名字,yyy则不是必须的,其值为节点的地址(寄存器地址或其他地址),比如i2c1: i2c@021a0000中的就是一个i2c控制器的寄存器基地址,rtc: pcf8523@68中的就是这个rtc设备的i2c地址
属性:地址
  • 有关节点的地址,比如i2c@021a0000,虽然它在名字后面跟了地址,但是正式的设置是在reg属性中设置的比如:reg = <0x021a0000 0x4000>; reg的格式通常为<address length>,0x021a0000是寄存器基地址,0x4000是长度。address 和length的个数是可变的,由父节点的属性#address-cells#size-cells 决定,比如节点i2c@021a0000的父节点是aips-bus@02000000,其#address-cells#size-cells均为1,所以下面的i2c节点的reg属性就有一个address 和length,而i2c节点本身#address-cells#size-cells 分别为1和0,所以其下的rtc: pcf8523@68 的reg属性就只有一个0x68(i2c地址)了
属性:兼容性
  • 如果一个节点是设备节点,那么它一定要有compatible(兼容性),因为这将作为驱动和设备(设备节点)的匹配依据,compatible(兼容性)的值可以有不止一个字符串以满足不同的需求,详见下一节。而根节点的compatible也是非常重要的,也就是"fsl,imx6dl"这个字符串,因为系统启动后,将根据根节点的compatible来判断cpu信息,并由此进行初始化
属性设置的套路

一般来说,每一种设备的节点属性设置都会有一些套路,比如可以设置哪些属性?属性值怎么设置?那怎么知道这些套路呢,有两种思路

  • 第一种是抄类似的dts,比如我们自己项目的平台是4412,那么就可以抄exynos4412-tiny4412.dts、exynos4412-smdk4412.dts这类相近的dts
  • 第二种是查询内核中的文档,比如Documentation/devicetree/bindings/i2c/i2c-imx.txt就描述了imx平台的i2c属性设置方法;Documentation/devicetree/bindings/fb就描述了lcd、lvds这类属性设置方法
节点之间的联系
  • 节点与节点之间的关联,通常通过“标号引用”和“包含”来实现
    • 所谓标号引用,就是在节点名称前加上标号,这样设备树的其他位置就能够通过&符号来调用/访问该节点,比如上面代码ir_recv节点中的gpio属性,就引用了gpio1标号处的节点
    • 包含则是最基本的方式,比如我们要在i2c1接口添加一个i2c外设,那么就必须要在i2c1下面添加一个节点,比如上面代码中的rtc: pcf8523@68 {}
  • 标号引用常常还作为节点的重写方式,比如下面代码是imx6qdl.dtsi中定义的i2c节点,而前面imx6dl-hummingboard.dts中的&i2c1,就是对i2c1标号处节点的一次重写,在其内部添加了一个rtc设备
  • 如果一个节点是属性节点(即仅仅是作为属性被其他节点调用),那么它定义在哪里其实无所谓,重要的是调用的位置,比如lcd屏幕的时序,其实我们完全可以把它定义在其他犄角旮旯,然后在lcd节点下用&来调用它,这也是可以的。这有点类似于函数:在哪定义不重要,重要的是在哪调用

3.内核(驱动)与节点的匹配

首先,内核必须要知道dtb文件的地址,这由U-boot来告诉内核,详见U-boot引导内核流程分析 https://blog.csdn.net/qq_28992301/article/details/51873201 第6节。只要内核知晓了dtb文件的地址,那么驱动就可以通过一些API任意获取设备树的内部信息

  • 对于3.x版本之后的内核,platform、i2c、spi等设备不再需要在mach-xxx中注册,驱动程序将直接和设备树里的设备节点进行配对,是通过设备节点中的compatible(兼容性)来与设备节点进行配对的,这里只做简单介绍,具体的应用详见 基于i2c子系统的驱动分析 https://blog.csdn.net/qq_28992301/article/details/52467766 、 基于platform总线的驱动分析 https://blog.csdn.net/qq_28992301/article/details/52385518
  • 这里以pcf8523驱动为例,只要驱动中的of_match_table 中的compatible 值和设备节点中的compatible 相匹配,那么probe函数就会被触发。不仅i2c是这样,platform、spi等都是这个原理
/*定义的of_match_table*/
static const struct of_device_id pcf8523_of_match[] = {
    { .compatible = "nxp,pcf8523" },
    { }
};

/*driver 结构体中的of_match_table*/
static struct i2c_driver pcf8523_driver = {
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(pcf8523_of_match),
    },
    .probe = pcf8523_probe,
    .id_table = pcf8523_id,
};
  • i2c和spi驱动还支持一种“别名匹配”的机制,就以pcf8523为例,假设某程序员在设备树中的pcf8523设备节点中写了compatible = "pcf8523";,显然相对于驱动id_table中的"nxp,pcf8523",他遗漏了nxp字段,但是驱动却仍然可以匹配上,因为别名匹配对compatible中字符串里第二个字段敏感

4.常见属性的设置与获取

当修改或编写驱动时,常常需要修改gpio、时钟、中断等等参数,以前都是在mach-xxx中的device设置的,现在则要在节点里设置,然后驱动用特殊的API来获取

  • 属性的获取常常在probe函数中进行,但是获取属性之前,最重要的是,确定哪个节点触发了驱动。如果一个驱动对应多个节点,那驱动可以通过int of_device_is_compatible(const struct device_node *device, const char *name)来判断当前节点是否包含指定的compatible(兼容性)
gpio的设置与获取
/*imx6dl.dtsi中gpio1控制器的定义节点*/
gpio1: gpio@0209c000 {
    compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio";
    reg = <0x0209c000 0x4000>;
    interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>,
             <0 67 IRQ_TYPE_LEVEL_HIGH>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;
    #interrupt-cells = <2>;
};

/*imx6qdl-sabreauto.dtsi中某个设备节点*/
max7310_reset: max7310-reset {
    compatible = "gpio-reset";
    reset-gpios = <&gpio1 15 1>;
    reset-delay-us = <1>;
    #reset-cells = <0>;
};
  • 一般来说,我们把gpio属性的名字起为xxx-gpios(xxx我们可以随便起),这样驱动才能通过特定API从识别该属性,并转换成具体的gpio号
  • 该设备节点中设置了reset-gpios = <&gpio1 15 1>;这格式是什么意思呢?&gpio1 15引用了gpio1节点,故此处含义为gpio1_15这个引脚;最后一个参数1则代表低电平有效,0则为高电平有效。至于gpio1_15具体对应哪个引脚,在imx6的手册上都有详细描述
  • 其实最后一个参数(高低电平有效)不是必须的,因为gpio1节点中设置了#gpio-cells = <2>;,所以才有两个参数;某些soc的gpio节点中会设置为#gpio-cells = <1>;,那么可以不写最后一个参数
  • 驱动一般通过以下接口获取上面节点中gpio的属性。该函数第一个参数是节点,一般可以在传入probe的参数中间接获得;第二个参数是gpio属性的名字,一定要和节点属性中的xxx-gpios相同;最后一个是编号index,当节点中有n个同名的xxx-gpios时,可以通过它来获取特定的那个gpio,同一节点中gpio同名情况很少存在,所以我们都把index设为0

    gpio = of_get_named_gpio(node, "reset-gpios", index);
  • 在dts和驱动都不关心gpio名字的情况下,也可直接通过以下接口来获取gpio号,这个时候编号index就十分重要了,可以指定拿取节点的第index个gpio属性
    gpio = of_get_gpio(node, index);
中断的设置与获取

假设某设备节点需要一个gpio中断

/*先确定中断所在的组*/
interrupt-parent = <&gpio6>;

/*表示中断,GPIO6中的第8个IO,2为触发类型,下降沿触发*/
interrupts = <8 2>;
  • 而在驱动中使用 中断号 =irq_of_parse_and_map(node, index)函数返回值来得到中断号
自定义属性的设置与获取

所谓的自定义属性,有点类似于老内核中的platform_data,我们在设备节点中可以随意添加自定义属性,比如下面这个节点里面的属性都是我们自己定义的

reg_3p3v: 3p3v {
    compatible = "regulator-fixed";
    regulator-name = "3P3V";
    regulator-min-microvolt = <3300000>;
    regulator-max-microvolt = <3300000>;
    regulator-always-on;
};
  • 针对32位整形的属性,比如上面的regulator-min-microvolt,可以利用下面这个API来获取属性值,第一个参数是节点,第二个参数是属性名字,第三个是输出型参数(把读出来的值放进去)

    of_property_read_u32(node, "regulator-min-microvolt", &microvolt);
  • 类似的读取数值的API还有:
int of_property_read_u8(const struct device_node *np, const char *propname, u8 *out_value)

int of_property_read_u16(const struct device_node *np, const char *propname, u16 *out_value)
  • 下列API可检查节点中某个属性是否存在,存在则返回true,不存在则返回false
bool of_property_read_bool(const struct device_node *np, const char *propname)
  • 当节点中存在字符串时,可以像下面那样读取,比如我们读取前面reg_3p3v节点中的字符串
of_property_read_string(node, "regulator-name", &string)
  • 当节点中存在数组时,可以像下面那样读取
/*带有数组的某个节点*/
L2: cache-controller@1e00a000 {
    compatible = "arm,pl310-cache";
    arm,data-latency = <1 1 1>;
    arm,tag-latency = <1 1 1>;
};

/*驱动中使用API来读取数组, &data为输出型参数*/
of_property_read_u32_array(node, "arm,pl310-cache", &data, ARRAY_SIZE(data));