linux设备驱动(6)--LED设备树字符驱动

代码学习资料来源于:

第7.1讲 设备树下的LED驱动试验-实验驱动框架搭建_哔哩哔哩_bilibili

仅用于个人学习/复习,侵联删

1、在根节点下添加下面的LED节点

alphaled {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "aplhaled,led";
    status = "okay";
    reg = < 0X020C406C 0x4    /* CCM_CCGR1_BASE */
            0X020E0068 0x4    /* SW_MUX_GPIO1_IO03_BAS */
            0X020E02F4 0x4    /* SW_PAD_GPIO1_IO03_BASE */
            0X0209C000 0x4    /* GPIO1_DR_BASE */
            0X0209C004 0x4 >;   /* GPIO1_GDIR_BASE */ 
};

创建完节点之后可以先在/proc/device-tree下查看是否存在alphaled节点

2、编写驱动

dtsled.c

此驱动没有编写地址映射的相关代码(仅用于个人学习/复习)。LED节点的寄存器信息通过数组来进行保存。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/parport.h>
#include <linux/ctype.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/major.h>
#include <linux/ppdev.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/compat.h>

#define DTSLED_COUNT 1
#define DTSLED_NAME "dtsled"

struct dtsled_device 
{
        dev_t devid;        /* 设备号 */
        struct cdev cdev;
        int major;        /* 主设备号 */
        int minor;
        struct class *class;        /* 类 */
        struct device *device;        /* 设备 */
        struct device_node *nd;        /* 设备节点 */
};

struct dtsled_device dtsled;

static const struct file_operations dtsled_fops = {
        .owner = THIS_MODULE;
        .write = dtsled_write;
        .open = dtsled_open;
        .release = dtsled_release;
}

static int __init dtsled_init(void)
{
        int ret = 0;
        
        /* 申请设备号 */
        dtsled.major = 0;
        if (dtsled.major) {
                dtsled.devid = MKDEV(dtsled.major, 0);        // 将主设备号和次设备号转换成设备号
                ret = register_chrdev_region(dtsled.devid, DTSLED_COUNT, DTSLED_NAME);
        } else {
                alloc_chrdev_region(&dtsled.devid, 0, DTSLED_COUNT, DTSLED_NAME);
                dtsled.major = MAJOR(dtsled.devid);
                dtsled.minor = MINOR(dtsled.devid);
        }

        if (ret < 0) {
                return -1;        
        }

        /* 添加字符设备 */
        dtsled.cdev.owner = THIS_MODULE;
        cdev_init(&dtsled.cdev, &dtsled_fops);
        ret = cdev_add(dtsled.cdev, dtsled.devid, DTSLED_COUNT);
        if (ret < 0) {
                unregister_chrdev_region(&dtsled.devid, DTSLED_COUNT);
                return -1;
        }
        
        /* 创建设备节点 */
        dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
        if (IS_ERR(dtsled.class)) {
                ret = PTR_ERR(dtsled.class);
                cdev_del(&dtsled.cdev);
                unregister_chrdev_region(dtsled.devid, DTSLED_COUNT);
                return ret;
        }

        dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
        if (IS_ERR(dtsled.device)) {
                ret = PTR_ERR(dtsled.device);
                cdev_del(&dtsled.cdev);
                unregister_chrdev_region(dtsled.devid, DTSLED_COUNT);
                class_destroy(dtsled.class);
                return ret;
        }

        dtsled.nd = of_find_node_by_path("/alphaled");
        if (dtsled.nd == NULL) {
                return -EINVAL;
                cdev_del(&dtsled.cdev);
                unregister_chrdev_region(dtsled.devid, DTSLED_COUNT);
                device_destroy(dtsled.class, dtsled.devid);
                class_destroy(dtsled.class);
        }

        u32 reg_data[10];
        ret = of_property_read_u32_array(nd, "reg", reg_data, 10);
        if (ret < 0) {
                printk("reg property failed \n");
                kfree(reg_data);
                return -1;
        } else {
                for (int i = 0; i < 10; i++) {
                        printk("reg[%d] = %d \n", i, reg_data[i]);
                }
        }

        return 0;
}

static void __exit dtsled_exit(void)
{
        /* 删除字符设备 */
        cdev_del(&dtsled.cdev);
        /* 释放设备号 */
        unregister_chrdev_region(dtsled.devid, DTSLED_COUNT);
        /* 销毁设备 */
        device_destroy(dtsled.class, dtsled.devid);
        /* 销毁类 */
        class_destroy(dtsled.class);
}

module_init(dtsled_init);
module_exit(dtsled_exit);

猜你喜欢

转载自blog.csdn.net/qq_58550520/article/details/129460338