这次用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

1302

被折叠的 条评论
为什么被折叠?



