基于GPIO子系统实现LED点亮驱动+应用程序测试

1.添加设备树子节点

/dts-v1/;
#include "stm32mp157.dtsi"
#include "stm32mp15xa.dtsi"
#include "stm32mp15-pinctrl.dtsi"
#include "stm32mp15xxac-pinctrl.dtsi"
#include "stm32mp15xx-fsmp1x.dtsi" 
/ {
        model = "HQYJ STM32MP157 FSMP1A Discovery Board";
        compatible = "st,stm32mp157a-dk1", "st,stm32mp157";

        aliases {
                serial0 = &uart4;
                serial5 = &usart3;
        };

        chosen {
                stdout-path = "serial0:115200n8";
        };

        reserved-memory {
                        gpu_reserved: gpu@d4000000 {
                                  reg = <0xd4000000 0x4000000>;
                                  no-map;
                          };

                        optee_memory: optee@0xde000000 {
                                  reg = <0xde000000 0x02000000>;
                                  no-map;
                          };
        };
    mynode@0x12345678{
        astring="hello 21091";
                uint  =<0xaabbccdd 0x11223344>;
        binarry=[00 0c 29 7b f9 be];
        mixed ="hello",[11 22],<0x12345678>;
         };

myled{
        led1-gpio=<&gpioe 10 0>;
        led2-gpio=<&gpiof 10 0>;
        led3-gpio=<&gpioe 8 0>;
};
};

2.编写驱动

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
// 主设备号
unsigned int major;
struct class *cls;
struct device *dev;

// 宏定命令码
#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)

struct device_node *dnode;
struct gpio_desc *gpiono[3];

int myled_open(struct inode *inode, struct file *file)
{
    // 判断次设备号
    int min = MINOR(inode->i_rdev);
    printk("min = %d\n",min);
    // 填充进file->private
    file->private_data = (void *)min;
    return 0;
}
int myled_close(struct inode *inode, struct file *file)
{
    return 0;
}
long myled_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int min = (int)file->private_data;
    switch (min)
    {
    case 0:
        switch (cmd)
        {
        case LED_ON:
            // 灯亮
            printk("这是一个调试信息  %d \n", __LINE__);
            gpiod_set_value(gpiono[0], 1);
            printk("这是一个调试信息  %d \n", __LINE__);
            break;
        case LED_OFF:
            // 灯灭
            gpiod_set_value(gpiono[0], 0);
            break;
        };
        break;
    case 1:
        switch (cmd)
        {
        case LED_ON:
            // 灯亮
            gpiod_set_value(gpiono[1], 1);
            break;
        case LED_OFF:
            // 灯灭
            gpiod_set_value(gpiono[1], 0);
            break;
        };
        break;
    case 2:
        switch (cmd)
        {
        case LED_ON:
            // 灯亮
            gpiod_set_value(gpiono[2], 1);
            break;
        case LED_OFF:
            // 灯灭
            gpiod_set_value(gpiono[2], 0);
            break;
        };
        break;
    }
    return 0;
}
struct file_operations fops = {
    .open = myled_open,
    .unlocked_ioctl = myled_ioctl,
    .release = myled_close,
};
static int __init myled_init(void)
{
    // 获取设备树节点
    dnode = of_find_node_by_path("/myled");
    if (dnode == NULL)
    {
        printk("解析设备树结点失败\n");
        return -ENXIO;
    }
    printk("解析设备树信息成功\n");
    // 获取GPIO编号
    gpiono[0] = gpiod_get_from_of_node(dnode, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);
    gpiono[1] = gpiod_get_from_of_node(dnode, "led2-gpio", 0, GPIOD_OUT_LOW, NULL);
    gpiono[2] = gpiod_get_from_of_node(dnode, "led3-gpio", 0, GPIOD_OUT_LOW, NULL);
    int i;
    for (i = 0; i < 3; i++)
    {
        if (IS_ERR(gpiono[i]))
        {
            printk("申请GPIO对象失败\n");
            return -ENXIO;
        }
    }
    printk("申请gpio对象成功\n");
    // 注册
    major = register_chrdev(0, "myled", &fops);
    if (major < 0)
    {
        printk("字符设备注册失败\n");
    }
    printk("字符设备注册成功 major:%d\n", major);

    // 自动创建设备节点
    cls = class_create(THIS_MODULE, "myled");
    if (IS_ERR(cls))
    {
        printk("向上提交目录信息失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录信息成功\n");
    // 创建设备节点
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i + 1);
        if (IS_ERR(dev))
        {
            printk("向上提交设备节点信息失败\n");
            return -PTR_ERR(dev);
        }
    }
    printk("向上提交设备节点信息成功\n");
    return 0;
}
static void __exit myled_exit(void)
{
    int i;
    // 灭灯
    for (i = 0; i < 3; i++)
    {
        gpiod_set_value(gpiono[i], 0);
    }

    // 释放GPIO编号
    for (i = 0; i < 3; i++)
    {
        gpiod_put(gpiono[i]);
    }
    // 销毁设备节点信息
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    printk("设备节点信息已销毁\n");
    // 销毁目录信息
    class_destroy(cls);
    printk("设备目录信息已销毁\n");

    unregister_chrdev(major, "mychrdev");
    printk("字符设备已注销\n");
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");

3.编写应用程序测试

#include <stdio.h>
// open函数头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// ioctl函数头文件
#include <sys/ioctl.h>
//exit
#include <stdlib.h>
//close
#include <unistd.h>
// 宏定命令码
#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)

int main(int argc, const char *argv[])
{
    // 1.选择操作哪盏灯
    unsigned int ledx;
    int fd;
    while (1)
    {
        printf("选择点亮哪盏灯?1:LED1  2:LED2  3:LED3\n");
        scanf("%d", &ledx);
        switch (ledx)
        {
        case 1:
            fd = open("/dev/myled1", O_RDWR);
            break;
        case 2:
            fd = open("/dev/myled2", O_RDWR);
            break;
        case 3:
            fd = open("/dev/myled3", O_RDWR);
            break;
        default:
            printf("请输出合法数值\n");
            continue;;
        }
        if (fd < 0)
        {
            printf("设备文件打开失败");
            exit(-1);
        }
        printf("成功打开myled%d\n", ledx);
        // 2.选择亮灭
        printf("亮或灭?1:亮 0:灭\n");
        scanf(" %d", &ledx);
        switch (ledx)
        {
        case 1:
            ioctl(fd, LED_ON);
            break;
        case 0:
            ioctl(fd, LED_OFF);
            break;
        default:
            printf("请输出合法数值\n");
            break;
        }
        close(fd);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值