linux platform 总线(设备树)驱动

发布于:2024-05-17 ⋅ 阅读:(105) ⋅ 点赞:(0)

使用文档

设备树修改

新增一个 LED 节点 arch/arm/boot/dts/arm/vexpress-v2p-ca9.dts

	my_pl_led {
		compatible = "cortex-a9-led";
		status = "okay";
	};

设备树编译

make dtbs

日志

  DTC     arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb

platform driver 源码

#include "linux/export.h"
#include "linux/ioport.h"
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>

#define PLATFORM_DEVICE_NAME "my_pl_led" /* 匹配设备树节点的名字 */

static int my_probe(struct platform_device *device)
{
    printk("platform driver probe\r\n");

    struct device_node *my_device_node;
    my_device_node = of_find_node_by_name(NULL, PLATFORM_DEVICE_NAME);
    if (my_device_node) {
        printk("device node name %s \r\n", my_device_node->name);
        /* 获取  compatible 属性的字符串。*/
        const char *compatible;
        compatible = of_get_property(my_device_node, "compatible", NULL);
        if (compatible) {
            printk("Compatible property: %s\n", compatible);
        } else {
            printk("Compatible property not found\n");
        }

        /* 获取  status 属性的字符串。*/
        compatible = of_get_property(my_device_node, "status", NULL);
        if (compatible) {
            printk("status property: %s\n", compatible);
        } else {
            printk("status property not found\n");
        }
    } else {
        printk("can't find device node\r\n");
    }

    return 0;
}

static int my_remove(struct platform_device *device)
{
    printk("platform driver remove\r\n");

    return 0;
}

/**
 * @brief include mod_devicetable.h.
 *
 */
static const struct platform_device_id test_id_table = {
    .name = PLATFORM_DEVICE_NAME, /* 和设备树匹配的名字。 */
};

/**
 * @brief include platform_device.h
 *
 */
static struct platform_driver platform_driver_test = {
    .probe = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "my_pl_driver", /* platform driver 的名字 */
        .owner = THIS_MODULE,
    },
    .id_table   = &test_id_table,
};

static int __init platform_driver_init(void)
{
    platform_driver_register(&platform_driver_test);

    printk("k: platform driver module init!\r\n");

    return 0;
}

static void __exit platform_driver_exit(void)
{
    platform_driver_unregister(&platform_driver_test);

    printk("k: platform driver module exit!\r\n");
}

module_init(platform_driver_init);
module_exit(platform_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyustli");
MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */

makefile 源码

# 指定内核路径
KERNELDIR := /home/tyustli/code/open_source/kernel/linux-6.5.7
# 指定当前路径
CURRENT_PATH := $(shell pwd)
# 指定编译的模块名
obj-m := my_platform_driver.o

build: kernel_modules

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

编译驱动

../my_module_build.sh ../0013_dtsplatform/

查看模块 ko 文件

ls /lib/modules/6.5.7+/
my_platform_driver.ko

查看 platform 设备

ls /sys/bus/platform/devices/my_pl_led/
driver_override       power                 waiting_for_supplier
modalias              subsystem
of_node               uevent

platform 驱动

如果编译报错

 error:const struct platform_device_id’ has no member named ‘name’

解决

#include <linux/mod_devicetable.h>

platform_device_id 结构体原型

struct platform_device_id {
	char name[PLATFORM_NAME_SIZE];
	kernel_ulong_t driver_data;
};

platform 驱动模块安装

modprobe my_platform_driver

匹配成功日志

platform driver probe
device node name my_pl_led 
Compatible property: cortex-a9-led
status property: okay
k: platform driver module init!
drm-clcd-pl111 10020000.clcd: DVI muxed to daughterboard 1 (core tile) CLCD
drm-clcd-pl111 10020000.clcd: initializing Versatile Express PL111

从结果可以看到 linux 6.5.7 版本的 platform driver 匹配的是 platform device 节点的名称,而不是 compatible 属性

查看 platform 驱动

ls /sys/bus/platform/drivers/my_pl_driver/
bind    module  uevent  unbind

退出

Ctrl + a
x