linux dts 学习笔记

这次用AI生成dts配置,并在驱动中将这些配置信息全部打印出来

驱动的makefile以前写过,有近8年没搞了,有点忘记,这次写一个笔记记录下

1. dts配置

我用的正点原子的imx6开发板,不知道内核是怎么编译的dtb,我就用现在dtb 反编译为dts,将新的dts配置写入到反编译后的dts后,在编译成dtb使用

dts
// my_test_device.dtsi
/ {
    my_test_device: my_test@0 {
        compatible = "my-company,my-test-device"; // 必须与驱动中的匹配
        status = "okay";                          // 设备状态

        // 各种类型的参数示例
        reg = <0x020ac000 0x4000>;                // 寄存器地址和大小
        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; // 中断信息

        // 字符串参数
        device-name = "imx6ull-test-device";
        manufacturer = "MyCompany";

        // 数值参数
        clock-frequency = <50000000>;             // 50MHz
        data-width = <32>;                        // 32位数据宽度
        timeout-ms = <1000>;                      // 超时时间1秒

        // 布尔参数(存在即为true)
        enable-dma;                               // DMA使能标志
        use-interrupt;                            // 使用中断

        // 数组参数
        gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>,      // GPIO数组
                <&gpio1 6 GPIO_ACTIVE_LOW>;

        // 自定义结构体参数
        custom-config {
            mode = "high-performance";
            voltage-level = <3300>;               // 3.3V
            temperature-threshold = <85>;         // 85°C
        };

        // 字符串列表
        supported-modes = "mode1", "mode2", "mode3";
    };
};

2. 驱动程序如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>

#define DRIVER_NAME "my_test_driver"

// 设备树匹配表
static const struct of_device_id my_test_of_match[] = {
    { .compatible = "my-company,my-test-device", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_test_of_match);

// 设备结构体
struct my_test_device {
    struct device *dev;
    const char *device_name;
    const char *manufacturer;
    u32 clock_frequency;
    u32 data_width;
    u32 timeout_ms;
    bool enable_dma;
    bool use_interrupt;
    u32 voltage_level;
    u32 temp_threshold;
    const char *mode;
    const char **supported_modes;
    int num_supported_modes;
    struct gpio_desc *gpio1;
    struct gpio_desc *gpio2;
};

// 解析字符串列表
static int parse_string_list(struct device_node *np, const char *prop_name,
                           const char ***list, int *count)
{
    int ret, i;
    
    ret = of_property_count_strings(np, prop_name);
    if (ret < 0) {
        return ret;
    }
    
    *count = ret;
    *list = devm_kcalloc(dev, *count, sizeof(char *), GFP_KERNEL);
    if (!*list) {
        return -ENOMEM;
    }
    
    for (i = 0; i < *count; i++) {
        ret = of_property_read_string_index(np, prop_name, i, &(*list)[i]);
        if (ret) {
            dev_err(dev, "Failed to read string %d from %s\n", i, prop_name);
            return ret;
        }
    }
    
    return 0;
}

// 探针函数
static int my_test_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct device_node *np = dev->of_node;
    struct device_node *child_np;
    struct my_test_device *test_dev;
    const char *mode;
    int ret, i;
    
    // 分配设备结构体
    test_dev = devm_kzalloc(dev, sizeof(*test_dev), GFP_KERNEL);
    if (!test_dev) {
        return -ENOMEM;
    }
    
    test_dev->dev = dev;
    platform_set_drvdata(pdev, test_dev);
    
    // 1. 读取字符串属性
    ret = of_property_read_string(np, "device-name", &test_dev->device_name);
    if (ret) {
        dev_err(dev, "Failed to read device-name\n");
        test_dev->device_name = "unknown";
    }
    
    ret = of_property_read_string(np, "manufacturer", &test_dev->manufacturer);
    if (ret) {
        dev_err(dev, "Failed to read manufacturer\n");
        test_dev->manufacturer = "unknown";
    }
    
    // 2. 读取数值属性
    ret = of_property_read_u32(np, "clock-frequency", &test_dev->clock_frequency);
    if (ret) {
        dev_warn(dev, "clock-frequency not specified, using default\n");
        test_dev->clock_frequency = 25000000; // 默认25MHz
    }
    
    ret = of_property_read_u32(np, "data-width", &test_dev->data_width);
    if (ret) {
        dev_warn(dev, "data-width not specified, using default\n");
        test_dev->data_width = 16; // 默认16位
    }
    
    ret = of_property_read_u32(np, "timeout-ms", &test_dev->timeout_ms);
    if (ret) {
        dev_warn(dev, "timeout-ms not specified, using default\n");
        test_dev->timeout_ms = 500; // 默认500ms
    }
    
    // 3. 读取布尔属性
    test_dev->enable_dma = of_property_read_bool(np, "enable-dma");
    test_dev->use_interrupt = of_property_read_bool(np, "use-interrupt");
    
    // 4. 读取GPIO
    test_dev->gpio1 = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN);
    if (IS_ERR(test_dev->gpio1)) {
        dev_warn(dev, "Failed to get GPIO1\n");
        test_dev->gpio1 = NULL;
    }
    
    test_dev->gpio2 = devm_gpiod_get_index(dev, NULL, 1, GPIOD_OUT_LOW);
    if (IS_ERR(test_dev->gpio2)) {
        dev_warn(dev, "Failed to get GPIO2\n");
        test_dev->gpio2 = NULL;
    }
    
    // 5. 读取子节点配置
    child_np = of_get_child_by_name(np, "custom-config");
    if (child_np) {
        ret = of_property_read_u32(child_np, "voltage-level", &test_dev->voltage_level);
        if (ret) {
            test_dev->voltage_level = 3000; // 默认3.0V
        }
        
        ret = of_property_read_u32(child_np, "temperature-threshold", &test_dev->temp_threshold);
        if (ret) {
            test_dev->temp_threshold = 75; // 默认75°C
        }
        
        ret = of_property_read_string(child_np, "mode", &test_dev->mode);
        if (ret) {
            test_dev->mode = "normal";
        }
        
        of_node_put(child_np);
    }
    
    // 6. 读取字符串列表
    ret = parse_string_list(np, "supported-modes", &test_dev->supported_modes, 
                          &test_dev->num_supported_modes);
    if (ret) {
        dev_warn(dev, "Failed to read supported-modes list\n");
        test_dev->num_supported_modes = 0;
    }
    
    // 打印所有读取到的参数
    printk(KERN_INFO "=== My Test Device Parameters ===\n");
    printk(KERN_INFO "Device Name: %s\n", test_dev->device_name);
    printk(KERN_INFO "Manufacturer: %s\n", test_dev->manufacturer);
    printk(KERN_INFO "Clock Frequency: %u Hz\n", test_dev->clock_frequency);
    printk(KERN_INFO "Data Width: %u bits\n", test_dev->data_width);
    printk(KERN_INFO "Timeout: %u ms\n", test_dev->timeout_ms);
    printk(KERN_INFO "DMA Enabled: %s\n", test_dev->enable_dma ? "yes" : "no");
    printk(KERN_INFO "Use Interrupt: %s\n", test_dev->use_interrupt ? "yes" : "no");
    printk(KERN_INFO "Voltage Level: %u mV\n", test_dev->voltage_level);
    printk(KERN_INFO "Temperature Threshold: %u °C\n", test_dev->temp_threshold);
    printk(KERN_INFO "Mode: %s\n", test_dev->mode);
    
    if (test_dev->gpio1) {
        printk(KERN_INFO "GPIO1: available\n");
    }
    if (test_dev->gpio2) {
        printk(KERN_INFO "GPIO2: available\n");
    }
    
    printk(KERN_INFO "Supported Modes (%d):\n", test_dev->num_supported_modes);
    for (i = 0; i < test_dev->num_supported_modes; i++) {
        printk(KERN_INFO "  - %s\n", test_dev->supported_modes[i]);
    }
    printk(KERN_INFO "=================================\n");
    
    dev_info(dev, "My test device probed successfully!\n");
    return 0;
}

// 移除函数
static int my_test_remove(struct platform_device *pdev)
{
    struct my_test_device *test_dev = platform_get_drvdata(pdev);
    
    printk(KERN_INFO "My test device removed\n");
    return 0;
}

// 平台驱动结构体
static struct platform_driver my_test_driver = {
    .probe = my_test_probe,
    .remove = my_test_remove,
    .driver = {
        .name = DRIVER_NAME,
        .of_match_table = my_test_of_match,
        .owner = THIS_MODULE,
    },
};

module_platform_driver(my_test_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Test driver for reading DTS parameters on i.MX6ULL");
MODULE_VERSION("1.0");

3. makefile文件如下:

KERNELDIR := /home/susu/work/imx/kernel
CURRENT_PATH := $(shell pwd)

obj-m := ds18b20.o

build: kernel_modules

kernel_modules:
        $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
        $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
 

4. 其他配置,因为我用的正点原子的开发板,交叉编译工具链在opt下,

这里贴出source的文件内容

susu@ubuntu:~/work/imx/dtds$ cat /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
export SDKTARGETSYSROOT=/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi
export PATH=/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/sbin:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/bin:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/sbin:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/../x86_64-pokysdk-linux/bin:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-uclibc:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-musl:$PATH
export CCACHE_PATH=/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/../x86_64-pokysdk-linux/bin:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-uclibc:/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-musl:$CCACHE_PATH
export PKG_CONFIG_SYSROOT_DIR=$SDKTARGETSYSROOT
export PKG_CONFIG_PATH=$SDKTARGETSYSROOT/usr/lib/pkgconfig
export CONFIG_SITE=/opt/fsl-imx-x11/4.1.15-2.1.0/site-config-cortexa7hf-neon-poky-linux-gnueabi
export OECORE_NATIVE_SYSROOT="/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux"
export OECORE_TARGET_SYSROOT="$SDKTARGETSYSROOT"
export OECORE_ACLOCAL_OPTS="-I /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/share/aclocal"
unset command_not_found_handle
export CC="arm-poky-linux-gnueabi-gcc  -march=armv7ve -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT"
export CXX="arm-poky-linux-gnueabi-g++  -march=armv7ve -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT"
export CPP="arm-poky-linux-gnueabi-gcc -E  -march=armv7ve -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT"
export AS="arm-poky-linux-gnueabi-as "
export LD="arm-poky-linux-gnueabi-ld  --sysroot=$SDKTARGETSYSROOT"
export GDB=arm-poky-linux-gnueabi-gdb
export STRIP=arm-poky-linux-gnueabi-strip
export RANLIB=arm-poky-linux-gnueabi-ranlib
export OBJCOPY=arm-poky-linux-gnueabi-objcopy
export OBJDUMP=arm-poky-linux-gnueabi-objdump
export AR=arm-poky-linux-gnueabi-ar
export NM=arm-poky-linux-gnueabi-nm
export M4=m4
export TARGET_PREFIX=arm-poky-linux-gnueabi-
export CONFIGURE_FLAGS="--target=arm-poky-linux-gnueabi --host=arm-poky-linux-gnueabi --build=x86_64-linux --with-libtool-sysroot=$SDKTARGETSYSROOT"
export LDFLAGS="-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed"
export CPPFLAGS=""
export KCFLAGS="--sysroot=$SDKTARGETSYSROOT"
export OECORE_DISTRO_VERSION="4.1.15-2.1.0"
export OECORE_SDK_VERSION="4.1.15-2.1.0"
export ARCH=arm
export CROSS_COMPILE=arm-poky-linux-gnueabi-

# Append environment subscripts
if [ -d "$OECORE_TARGET_SYSROOT/environment-setup.d" ]; then
    for envfile in $OECORE_TARGET_SYSROOT/environment-setup.d/*.sh; do
            . $envfile
    done
fi
if [ -d "$OECORE_NATIVE_SYSROOT/environment-setup.d" ]; then
    for envfile in $OECORE_NATIVE_SYSROOT/environment-setup.d/*.sh; do
            . $envfile
    done
fi
susu@ubuntu:~/work/imx/dtds$
 

5. 驱动加载后的打印信息如下,本文只是记录了一些dts解析的东西,因为有近8年没搞了,当时还是2013年dts刚刚开始出来的时候接触了dts,这里写下这个文章防止遗忘。

root@ATK-IMX6U:/mnt# dmesg
[ 3000.010850] my_test_driver 20ac000.my_test: Failed to get GPIO1
[ 3000.019519] my_test_driver 20ac000.my_test: Failed to get GPIO2
[ 3000.026585] === My Test Device Parameters ===
[ 3000.030972] Device Name: imx6ull-test-device
[ 3000.038781] Manufacturer: MyCompany
[ 3000.044268] Clock Frequency: 50000000 Hz
[ 3000.048388] Data Width: 32 bits
[ 3000.051667] Timeout: 1000 ms
[ 3000.055474] DMA Enabled: yes
[ 3000.058383] Use Interrupt: yes
[ 3000.061443] Voltage Level: 3300 mV
[ 3000.065688] Temperature Threshold: 85 °C
[ 3000.069723] Mode: high-performance
[ 3000.073758] Supported Modes (0):
[ 3000.077006] =================================
[ 3000.081380] my_test_driver 20ac000.my_test: My test device probed successfully!
[ 3004.922796] My test device removed
root@ATK-IMX6U:/mnt#
Network error: Software caused connection abort

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值