zynq 是不是有了设备树,再linux中不需要编写驱动也能控制

不完全是。设备树不能完全替代驱动,但它极大地简化了驱动的编写和使用。

设备树 vs. 驱动的关系

1. 设备树的作用:描述"有什么"

设备树只描述硬件配置:

有什么硬件设备

设备在哪个地址

使用哪些中断、GPIO、时钟

设备的参数和选项

bash 复制代码
dts
// 设备树只描述,不实现功能
led0 {
    label = "user-led";
    gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
};

2. 驱动的作用:实现"怎么用"

驱动包含控制硬件的代码逻辑:

如何初始化设备

如何读写数据

如何处理中断

提供用户空间接口

bash 复制代码
c
// 驱动实现功能
static int led_probe(struct platform_device *pdev)
{
    // 从设备树获取GPIO信息
    led->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
    
    // 提供用户空间接口
    led->cdev.brightness_set = led_brightness_set;
    led_classdev_register(&pdev->dev, &led->cdev);
    
    return 0;
}

实际情况分析

情况1:标准设备 + 通用驱动 = 无需编写新驱动

有些设备有通用驱动,设备树配置后即可使用:

bash 复制代码
dts
// 设备树配置
leds {
    compatible = "gpio-leds";  // 使用内核已有的通用LED驱动
    
    power_led {
        label = "power";
        gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
        default-state = "on";
        linux,default-trigger = "heartbeat";
    };
};

gpio-keys {
    compatible = "gpio-keys";  // 使用内核已有的按键驱动
    
    button {
        label = "User Button";
        gpios = <&gpio0 50 GPIO_ACTIVE_LOW>;
        linux,code = <KEY_ENTER>;
    };
};

✅ 这种情况:添加设备树配置后,内核已有的驱动会自动识别并控制设备。

✅ 用户空间:可以直接通过 /sys/class/leds/ 或 /dev/input/eventX 使用设备。

情况2:自定义设备 = 必须编写驱动

bash 复制代码
dts
// 设备树配置
my_custom_device@0 {
    compatible = "mycompany,mydevice";  // 需要对应的驱动
    
    reg = <0x12340000 0x1000>;
    interrupt-parent = <&gic>;
    interrupts = <0 45 4>;
    custom-param = <100>;
};

❌ 这种情况:必须编写驱动实现 mycompany,mydevice 的匹配和处理。

哪些设备可以"无驱动"使用?

  1. 内核已有通用驱动的设备:
    设备类型 兼容字符串 用户空间接口
bash 复制代码
GPIO LED	"gpio-leds"	/sys/class/leds/
GPIO 按键	"gpio-keys"	/dev/input/eventX
PWM LED	"pwm-leds"	/sys/class/leds/
RTC时钟	"ds1307"	/dev/rtc0
EEPROM	"at24"	/sys/bus/i2c/devices/
看门狗	"wdog"	/dev/watchdog
温度传感器	"lm75"	/sys/class/hwmon/
  1. 用户空间直接访问的设备:
    bash

GPIO直接访问(不推荐生产环境)

bash 复制代码
echo 23 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio23/direction
echo 1 > /sys/class/gpio/gpio23/value

I2C设备直接访问

bash 复制代码
i2cset -y 1 0x50 0x00 0x12  # 写I2C设备
i2cget -y 1 0x50 0x00       # 读I2C设备

SPI设备直接访问

spidev_test -D /dev/spidev1.0 -v

  1. 通过libgpiod等库访问:
c 复制代码
c
// 用户空间C程序
#include <gpiod.h>
int main() {
    struct gpiod_chip *chip = gpiod_chip_open("/dev/gpiochip0");
    struct gpiod_line *line = gpiod_chip_get_line(chip, 23);
    gpiod_line_request_output(line, "example", 0);
    gpiod_line_set_value(line, 1);
    return 0;
}

实际工作流程示例

场景:添加一个新的LED

bash 复制代码
dts
// 步骤1:设备树中添加LED描述
/dts-v1/;
/ {
    leds {
        compatible = "gpio-leds";
        
        my_led {
            label = "my-led";
            gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>;
            default-state = "off";
        };
    };
};

bash

步骤2:编译并加载设备树

bash 复制代码
dtc -O dtb -o myboard.dtb myboard.dts

通过bootloader加载或动态加载

步骤3:无需编写驱动,直接使用

bash 复制代码
ls /sys/class/leds/

my_led 会出现

步骤4:从用户空间控制

bash 复制代码
echo 1 > /sys/class/leds/my_led/brightness  # 打开LED
echo 0 > /sys/class/leds/my_led/brightness  # 关闭LED
echo heartbeat > /sys/class/leds/my_led/trigger  # 设置为心跳闪烁

需要编写驱动的情况

场景:自定义的传感器设备

bash 复制代码
dts
// 设备树
my_sensor@1 {
    compatible = "mycompany,sensor-v1";
    reg = <0x76>;
    interrupt-parent = <&gpio0>;
    interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
    measurement-interval-ms = <1000>;
};
c 复制代码
c
// 必须编写驱动
static const struct of_device_id sensor_of_match[] = {
    { .compatible = "mycompany,sensor-v1" },
    { }
};

static struct i2c_driver sensor_driver = {
    .probe = sensor_probe,
    .id_table = sensor_id,
    .driver = {
        .name = "my_sensor",
        .of_match_table = sensor_of_match,
    },
};

// 必须实现probe、read、write等函数
static int sensor_probe(struct i2c_client *client)
{
    // 从设备树获取参数
    of_property_read_u32(np, "measurement-interval-ms", &interval);
    
    // 初始化硬件
    // 注册字符设备或sysfs接口
    // 设置中断处理函数
}

现代Linux的趋势

  1. 设备树绑定标准化
    越来越多的设备有标准绑定,减少自定义驱动需求:
bash 复制代码
dts
// IIO(工业IO)传感器标准绑定
adc@0 {
    compatible = "ti,ads1015";
    reg = <0x48>;
    #address-cells = <1>;
    #size-cells = <0>;
    
    channel@4 {
        reg = <4>;
        ti,gain = <3>;
        ti,datarate = <5>;
    };
};
  1. 用户空间驱动框架
    有些设备可以在用户空间处理:
    UIO(Userspace I/O):将设备映射到用户空间
    VFIO:虚拟化环境中的设备直通

libgpiod:用户空间GPIO控制

  1. 设备树覆盖
    运行时修改设备树,无需重新编译内核:

bash

动态添加设备

bash 复制代码
dtoverlay my-device-overlay.dtbo

总结对比

方面 设备树 驱动

作用 硬件描述 功能实现

内容 硬件配置参数 控制逻辑代码

位置 编译时/启动时加载 内核模块或内置

修改 修改文本文件 编写C代码

示例 gpios = <&gpio0 23 0> gpiod_set_value(gpio, 1)

结论

对于标准设备:设备树 + 内核已有驱动 = 无需编写驱动

GPIO LED、按键、标准I2C设备等

对于自定义设备:设备树 + 自定义驱动 = 必须编写驱动

专用传感器、自定义通信协议设备等

简单控制:有时可以在用户空间直接操作

GPIO、I2C、SPI的简单读写

相关推荐
一叶星殇3 小时前
.NET WebAPI:用 Nginx 还是 IIS 更好
运维·nginx·.net
LUCIFER4 小时前
[驱动进阶——MIPI摄像头驱动(五)]rk3588+OV13855摄像头驱动加载过程详细解析第四部分——ISP驱动
linux·驱动开发
暮云星影4 小时前
四、linux系统 应用开发:UI开发环境配置概述 (一)
linux·ui·arm
DLGXY5 小时前
STM32——EXTI外部中断(六)
stm32·单片机·嵌入式硬件
a程序小傲5 小时前
得物Java面试被问:RocketMQ的消息轨迹追踪实现
java·linux·spring·面试·职场和发展·rocketmq·java-rocketmq
Ghost Face...5 小时前
i386 CPU页式存储管理深度解析
java·linux·服务器
Trank-Lw5 小时前
Docker Devcontainer 管理命令
运维·docker·容器
RisunJan5 小时前
Linux命令-less(分页查看器)
linux·运维
赛希咨询5 小时前
人工智能自动化如何提高研究生产力
运维·人工智能·自动化