当前位置: 首页 > article >正文

[linux驱动开发--API框架]--platform、gpio、pinctrl

1. 结构体定义和实例化

// 这个结构体样式并不固定,按需增减成员,可以参考内核的其他驱动代码
struct leddev_dev{
    dev_t devid;                /* 设备号*/
    struct cdev cdev;           /* cdev*/
    struct class *class;        /* 类*/
    struct device *device;      /* 设备*/
    int major;                  /* 主设备号*/	
    struct device_node *node;   /* LED设备节点*/
    int led0;                   /* LED灯GPIO标号*/
}leddev;

/*这个结构体最少也要有这些成员,可以参考内核的驱动代码*/
struct platform_driver led_platform_driver = {
    .probe = led_probe,
    .driver = {
            .name = "leds-platform_gpio",
            .owner = THIS_MODULE,
            .of_match_table = led_ids,
    }
};

2. 注册与卸载配套API

注意:顺序注册,逆序卸载

  1. 执行led_platform_driver_initled_platform_driver_exit函数
module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);
  1. 注册卸载平台驱动
DriverState = platform_driver_register(&led_platform_driver);
platform_driver_unregister(&led_platform_driver);
  1. /proc/devices/LEDDEV_NAME下生成名称对应LEDDEV_NAME的主设备号
alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
unregister_chrdev_region(leddev.devid, LEDDEV_CNT);
cdev_init(&leddev.cdev, &led_fops);
cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
cdev_del(&leddev.cdev);	
  1. /sys/class/LEDDEV_NAME下创建类
leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
class_destroy(leddev.class);
  1. /dev/LEDDEV_NAME下创建设备节点,在/sys/devices/virtual/gpio_lab_led下创建设备
leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
device_destroy(leddev.class, leddev.devid);
  1. 试验了一下,现在的内核不需要显式释放leddev.led0
leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
gpio_direction_output(leddev.led0, 1);

3. 完整代码(仅供参考)

#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#define LEDDEV_CNT      1
#define LEDDEV_NAME     "gpio_lab_led"
/* leddev设备结构体 */
struct leddev_dev{
	dev_t devid;				/* 设备号	*/
	struct cdev cdev;			/* cdev		*/
	struct class *class;		/* 类 		*/
	struct device *device;		/* 设备		*/
	int major;					/* 主设备号	*/	
	struct device_node *node;	/* LED设备节点 */
	int led0;					/* LED灯GPIO标号 */
};

struct leddev_dev leddev; 		/* led设备 */

static int led_open(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	return 0;
}

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

/*----------------平台驱动函数集-----------------*/
static int led_probe(struct platform_device *pdv)
{
    printk(KERN_EMERG "led driver and device was matched!\r\n");
    // 注册的设备ID保存到leddev.devid
    // LEDDEV_NAME对应/proc/devices下的名字
    alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
    leddev.major = MAJOR(leddev.devid);
    printk(KERN_EMERG "\tleddev.major = %d\n",leddev.major);
    // 绑定操作函数
    cdev_init(&leddev.cdev, &led_fops);
    // 绑定设备ID
	cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
    /* 3、创建类      */
	leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
	if (IS_ERR(leddev.class)) {
		return PTR_ERR(leddev.class);
	}
	/* 4、创建设备 */
	leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
	if (IS_ERR(leddev.device)) {
		return PTR_ERR(leddev.device);
	}

    leddev.node = of_find_node_by_path("/lab_led");
    if(leddev.node == NULL)
    {
        printk(KERN_EMERG "get lab_led failed!  \n");
    }

    leddev.led0 = of_get_named_gpio(leddev.node, "gpios", 0);

    printk("led = %d \n",leddev.led0);

    /*设置gpio输出高电平*/
    gpio_direction_output(leddev.led0, 1);
    return 0;
}

static const struct of_device_id led_ids[] = {
    { .compatible = "gpio_lab_led"},
    { /* sentinel */ }
};

/*定义平台设备结构体*/
struct platform_driver led_platform_driver = {
    .probe = led_probe,
    .driver = {
            .name = "leds-platform_gpio",
            .owner = THIS_MODULE,
            .of_match_table = led_ids,
    }
};

/*
*驱动初始化函数
*/
static int __init led_platform_driver_init(void)
{
    int DriverState;
    DriverState = platform_driver_register(&led_platform_driver);
    printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
    return 0;
}

/*
*驱动注销函数
*/
static void __exit led_platform_driver_exit(void)
{
    printk(KERN_EMERG "led_test exit!\n");
	gpio_direction_output(leddev.led0, 0);
	device_destroy(leddev.class, leddev.devid);
	class_destroy(leddev.class);
    cdev_del(&leddev.cdev);				/*  删除cdev */
	unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
    platform_driver_unregister(&led_platform_driver);
}
module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);

MODULE_LICENSE("GPL");

http://www.kler.cn/a/386199.html

相关文章:

  • 深度学习在边缘检测中的应用及代码分析
  • 基于GPU器件行为的创新分布式功能安全机制为智能驾驶保驾护航
  • BILSTM法律网站用户提问自动分类
  • STM32中,不进行printf改写通过函数达到同款效果
  • 408笔记合集
  • Dolby TrueHD和Dolby Digital Plus (E-AC-3)编码介绍
  • go语言中的结构体含义和用法详解
  • 打印沙漏的4种解法(直接法编程、艺术化编程)
  • 如何使用SSH密钥和公钥加密技术保护您的cPanel服务器
  • 【Linux】一篇文章轻松搞懂基本指令
  • Dinky控制台:利用SSE技术实现实时日志监控与操作
  • QT中QML学习笔记2
  • HarmonyOS 总结
  • VMware+Ubuntu+finalshell连接
  • 【C++】【算法基础】快速排序
  • cocos creator 3.8.3物理组件分组的坑
  • RocketMQ部署教程
  • 力扣第39题:组合总和(C语言解法)
  • 基于springboot的作业管理系统设计与实现
  • Linux基础-1
  • Linux Centos7 如何安装图形化界面
  • LVSM: A LARGE VIEW SYNTHESIS MODEL WITH MINIMAL 3D INDUCTIVE BIAS 论文解读
  • (Go语言)Go基础的进阶知识!带你认识迭代器与类型以及声明并使用接口与泛型!
  • web实操2——idea创建普通web项目
  • FilterListener组件
  • SSH实验5密钥登录Linuxroot用户(免密登录)