蚂蚁S9矿板PS 内核定时器驱动

参考

蚂蚁S9矿板引脚定义.csdn

设备树

system-user.dtsi

bash 复制代码
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/media/xilinx-vip.h>
#include <dt-bindings/phy/phy.h>

/ {
	model = "z7 Board ant 789";
	compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";
	chosen {
		bootargs = "console=ttyPS0,115200 earlycon=cdns,mmio,0xe0000000,115200n8 keep_bootcon earlyprintk root=/dev/mmcblk0p2 rw rootwait";
		stdout-path = "serial0:115200n8";
	};

 	led{
		compatible="ming,led";
		status="okay";
		default-state="on";
        led-gpio = <&gpio0 37 GPIO_ACTIVE_HIGH>;
	};

	beeper{
		compatible = "ming,beeper";
		status = "okay";
		default-state = "off";
		beeper-gpio = <&gpio0 38 GPIO_ACTIVE_HIGH>;
	};

	key {
		compatible = "ming,key";
		status = "okay";
		key-gpio = <&gpio0 47 GPIO_ACTIVE_LOW>;
	};
};

驱动 timer.c

c 复制代码
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
#include <linux/types.h>

#define LED_CNT			1		/* 设备号个数 */
#define LED_NAME		"led"	/* 名字 */

/* ioctl函数命令定义 */
#define CMD_LED_CLOSE	(_IO(0XEF, 0x1))		/* 关闭LED */
#define CMD_LED_OPEN	(_IO(0XEF, 0x2))		/* 打开LED */
#define CMD_SET_PERIOD	(_IO(0XEF, 0x3))		/* 设置LED闪烁频率 */


/* led设备结构体 */
struct led_dev {
    dev_t devid;				/* 设备号 */
    struct cdev cdev;			/* cdev */
    struct class *class;		/* 类 */
    struct device *device;		/* 设备 */
    int major;					/* 主设备号 */
    int minor;					/* 次设备号 */
    struct device_node *nd;		/* 设备节点 */
    int led_gpio;				/* GPIO编号 */
    int period;					/* 定时周期,单位为ms */
    struct timer_list timer;	/* 定义一个定时器 */
    spinlock_t spinlock;		/* 定义自旋锁 */
};

static struct led_dev led;	/* led设备 */

/*
 * @description			: 打开设备
 * @param -- inode		: 传递给驱动的inode
 * @param -- filp		: 设备文件,file结构体有个叫做private_data的成员变量
 * 						 一般在open的时候将private_data指向设备结构体。
 * @return				: 0 成功;其他 失败
 */
static int led_open(struct inode *inode, struct file *filp)
{
    return 0;
}

/*
 * @description			: 从设备读取数据 
 * @param -- filp		: 要打开的设备文件(文件描述符)
 * @param -- buf			: 返回给用户空间的数据缓冲区
 * @param -- cnt			: 要读取的数据长度
 * @param -- offt		: 相对于文件首地址的偏移
 * @return				: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t led_read(struct file *filp, char __user *buf,
            size_t cnt, loff_t *offt)
{
    return 0;
}

/*
 * @description			: 向设备写数据 
 * @param -- filp		: 设备文件,表示打开的文件描述符
 * @param -- buf			: 要写给设备写入的数据
 * @param -- cnt			: 要写入的数据长度
 * @param -- offt		: 相对于文件首地址的偏移
 * @return				: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t led_write(struct file *filp, const char __user *buf,
            size_t cnt, loff_t *offt)
{
    return 0;
}

/*
 * @description			: 关闭/释放设备
 * @param -- filp		: 要关闭的设备文件(文件描述符)
 * @return				: 0 成功;其他 失败
 */
static int led_release(struct inode *inode, struct file *filp)
{
    return 0;
}

/*
 * @description			: ioctl函数,
 * @param -- filp		: 要打开的设备文件(文件描述符)
 * @param -- cmd			: 应用程序发送过来的命令
 * @param -- arg			: 参数
 * @return				: 0 成功;其他 失败
 */
static long led_unlocked_ioctl(struct file *filp, unsigned int cmd,
            unsigned long arg)
{
    unsigned long flags;

    /* 自旋锁上锁 */
    spin_lock_irqsave(&led.spinlock, flags);

    switch (cmd) {

    case CMD_LED_CLOSE:
        del_timer_sync(&led.timer);
        gpio_set_value(led.led_gpio, 0);
        break;

    case CMD_LED_OPEN:
        del_timer_sync(&led.timer);
        gpio_set_value(led.led_gpio, 1);
        break;

    case CMD_SET_PERIOD:
        led.period = arg;
        mod_timer(&led.timer, jiffies + msecs_to_jiffies(arg));
        break;

    default: break;
    }

    /* 自旋锁解锁 */
    spin_unlock_irqrestore(&led.spinlock, flags);

    return 0;
}

/* 设备操作函数 */
static struct file_operations led_fops = {
    .owner				= THIS_MODULE,
    .open				= led_open,
    .read				= led_read,
    .write				= led_write,
    .release			= led_release,
    .unlocked_ioctl	= led_unlocked_ioctl,
};

/* 定时器回调函数 */
static void led_timer_function(struct timer_list *unused)
{
    static bool on = 1;
    unsigned long flags;

    /* 每次都取反,实现LED灯反转 */
    on = !on;

    /* 自旋锁上锁 */
    spin_lock_irqsave(&led.spinlock, flags);

    /* 设置GPIO电平状态 */
    gpio_set_value(led.led_gpio, on);

    /* 重启定时器 */
    mod_timer(&led.timer, jiffies + msecs_to_jiffies(led.period));

    /* 自旋锁解锁 */
    spin_unlock_irqrestore(&led.spinlock, flags);
}

static int __init led_init(void)
{
    const char *str;
    int val;
    int ret;

    /* 初始化自旋锁 */
    spin_lock_init(&led.spinlock);

    /* 1.获取led设备节点 */
    led.nd = of_find_node_by_path("/led");
    if(NULL == led.nd) {
        printk(KERN_ERR "led: Failed to get led node\n");
        return -EINVAL;
    }

    /* 2.读取status属性 */
    ret = of_property_read_string(led.nd, "status", &str);
    if(!ret) {
        if (strcmp(str, "okay"))
            return -EINVAL;
    }

    /* 3.获取compatible属性值并进行匹配 */
    ret = of_property_read_string(led.nd, "compatible", &str);
    if(ret) {
        printk(KERN_ERR "led: Failed to get compatible property\n");
        return ret;
    }

    if (strcmp(str, "ming,led")) {
        printk(KERN_ERR "led: Compatible match failed\n");
        return -EINVAL;
    }

    printk(KERN_INFO "led: device matching successful!\r\n");

    /* 4.获取设备树中的led-gpio属性,得到LED所使用的GPIO编号 */
    led.led_gpio = of_get_named_gpio(led.nd, "led-gpio", 0);
    if(!gpio_is_valid(led.led_gpio)) {
        printk(KERN_ERR "led: Failed to get led-gpio\n");
        return -EINVAL;
    }

    printk(KERN_INFO "led: led-gpio num = %d\r\n", led.led_gpio);

    /* 5.向gpio子系统申请使用GPIO */
    ret = gpio_request(led.led_gpio, "LED Gpio");
    if (ret) {
        printk(KERN_ERR "led: Failed to request led-gpio\n");
        return ret;
    }

    /* 6.设置LED灯初始状态 */
    ret = of_property_read_string(led.nd, "default-state", &str);
    if(!ret) {
        if (!strcmp(str, "on"))
            val = 1;
        else
            val = 0;
    } else
        val = 0;

    gpio_direction_output(led.led_gpio, val);

    /* 7.注册字符设备驱动 */
     /* 创建设备号 */
    if (led.major) {
        led.devid = MKDEV(led.major, 0);
        ret = register_chrdev_region(led.devid, LED_CNT, LED_NAME);
        if (ret)
            goto out1;
    } else {
        ret = alloc_chrdev_region(&led.devid, 0, LED_CNT, LED_NAME);
        if (ret)
            goto out1;

        led.major = MAJOR(led.devid);
        led.minor = MINOR(led.devid);
    }

    printk(KERN_INFO "led: major=%d, minor=%d\r\n", led.major, led.minor);

     /* 初始化cdev */
    led.cdev.owner = THIS_MODULE;
    cdev_init(&led.cdev, &led_fops);

     /* 添加cdev */
    ret = cdev_add(&led.cdev, led.devid, LED_CNT);
    if (ret)
        goto out2;

     /* 创建类 */
    led.class = class_create(THIS_MODULE, LED_NAME);
    if (IS_ERR(led.class)) {
        ret = PTR_ERR(led.class);
        goto out3;
    }

     /* 创建设备 */
    led.device = device_create(led.class, NULL,
                led.devid, NULL, LED_NAME);
    if (IS_ERR(led.device)) {
        ret = PTR_ERR(led.device);
        goto out4;
    }

    /* 8.初始化timer,绑定定时器处理函数,此时还未设置周期,所以不会激活定时器 */
    timer_setup(&led.timer,led_timer_function,0);

    return 0;

out4:
    class_destroy(led.class);

out3:
    cdev_del(&led.cdev);

out2:
    unregister_chrdev_region(led.devid, LED_CNT);

out1:
    gpio_free(led.led_gpio);

    return ret;
}

static void __exit led_exit(void)
{
    /* 删除定时器 */
    del_timer_sync(&led.timer);

    /* 注销设备 */
    device_destroy(led.class, led.devid);

    /* 注销类 */
    class_destroy(led.class);

    /* 删除cdev */
    cdev_del(&led.cdev);

    /* 注销设备号 */
    unregister_chrdev_region(led.devid, LED_CNT);

    /* 释放GPIO */
    gpio_free(led.led_gpio);
}

/* 驱动模块入口和出口函数注册 */
module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("DengTao <773904075@qq.com>");
MODULE_DESCRIPTION("ming Gpio LED Driver");
MODULE_LICENSE("GPL");

timerApp.c

c 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>

/* ioctl命令 */
#define CMD_LED_CLOSE      (_IO(0XEF, 0x1))     /* 关闭LED */
#define CMD_LED_OPEN       (_IO(0XEF, 0x2))     /* 打开LED */
#define CMD_SET_PERIOD     (_IO(0XEF, 0x3))     /* 设置LED闪烁频率 */

/*
 * @description			: main主程序
 * @param -- argc		: argv数组元素个数
 * @param -- argv		: 具体参数
 * @return				: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
    int fd, ret;
    unsigned int cmd;
    unsigned int period;

    if(2 != argc) {
        printf("Usage:\n"
               "\t./timerApp /dev/led   @ open LED device\n"
        );
        return -1;
    }

    /* 打开设备 */
    fd = open(argv[1], O_RDWR);
    if(0 > fd) {
        printf("ERROR: %s file open failed!\r\n", argv[1]);
        return -1;
    }

    /* 通过命令控制LED设备 */
    for ( ; ; ) {

        printf("Input CMD:");
        scanf("%d", &cmd);

        switch (cmd) {

        case 0:
            cmd = CMD_LED_CLOSE;
            break;

        case 1:
            cmd = CMD_LED_OPEN;
            break;

        case 2:
            cmd = CMD_SET_PERIOD;
            printf("Input Timer Period:");
            scanf("%d", &period);
            break;

        case 3:
            close(fd);
            return 0;

        default: break;
        }

        ioctl(fd, cmd, period);
    }
}

编译驱动和app

bash 复制代码
$CC -o timerApp timerApp.c

测试

bash 复制代码
root@ant:~# insmod timer.ko
led: device matching successful!
led: led-gpio num = 943
led: major=244, minor=0
root@ant:~# ls /dev/led
/dev/led
root@ant:~# chmod 777 timerApp
root@ant:~# ./timerApp /dev/led
Input CMD:1
Input CMD:2
Input Timer Period:100
Input CMD:
相关推荐
你想知道什么?1 小时前
决策树-学习笔记
笔记·学习·决策树
MartinYeung51 小时前
[论文学习]WASP:面向提示注入攻击的Web代理安全性基准测试
前端·网络·学习
懒狗跑ai的程序员Brain2 小时前
如何利用粒子系统在unity制作一个烟花(粒子系统学习向)
学习·unity·游戏引擎
念何架构之路2 小时前
moby-BuildKit(builder-next)
学习·docker·容器
惠惠软件2 小时前
快速生成磁盘目录文件-双击运行a.bat ,可以看到磁盘目录下出现了 文件目录.txt-供大家学习研究参考
windows·学习·文件列表
星恒随风2 小时前
C++ STL 详解:set 与 multiset 的使用、区间查询和算法应用
开发语言·c++·笔记·学习·算法
m4Rk_2 小时前
【论文阅读】Agent 记忆机制(20):RecMem——只在信息反复出现时进行长期记忆巩固
论文阅读·人工智能·学习·开源·github
菩提树下的打坐2 小时前
测试工程与 DevOps / SRE 的边界:三方协作的真实工作流
学习
幸福在路上wellbeing2 小时前
AI 智能体开发 · Day 2 详细学习手册
人工智能·学习