pinctrl 和 gpio 子系统的字符设备驱动

  • 一、 修改设备树文件
  • 二、 LED 灯驱动程序编写
  • 三、makefile
  • 四、应用层代码
  • 运行测试

一、 修改设备树文件

打开 imx6ull-alientekemmc.dts,在根节点“/”下创建 LED 灯节点,节点名为“gpioled”。

/*yqh2021/5/12*/gpioled{compatible = "alientek,gpioled";pinctrl-name = "default";pinctrl-0 = <&pinctrl_gpioled>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;status = "okay";};

打开 imx6ull-alientekemmc.dts,在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_led”的子节点。

/*yqh2021/5/12*/pinctrl_gpioled: ledgrp{fsl,pihs = <MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10b0>;};

在 imx6ull-alientek-emmc.dts 中找到如下内容,屏蔽gpio1_3

pinctrl_tsc: tscgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO01__GPIO1_IO01    0xb0MX6UL_PAD_GPIO1_IO02__GPIO1_IO02    0xb0/*YQH 2021/5/12*//*MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0*/MX6UL_PAD_GPIO1_IO04__GPIO1_IO04  0xb0>;};
&tsc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_tsc>;/*YQH 2021/5/12*//*xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;*/measure-delay-time = <0xffff>;pre-charge-time = <0xfff>;status = "okay";
};

设备树编写完成以后使用“make dtbs”命令重新编译设备树,然后使用新编译出来的imx6ull-alientek-emmc.dtb 文件启动 Linux 系统。
使用新生成的设备树 进入查看节点是否存在。

sudo cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /home/yqh/linux/tftpboot/ -f
cd /proc/device-tree/
ls

二、 LED 灯驱动程序编写

/*参照linux内核去写驱动*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kernel.h>                        //printk需要包含的头文件
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>/*注册字符设备个数*/
#define GPIOLED_CNT     1
/*注册字符设备名字*/
#define GPIOLED_NAME    "gpioled"
#define LEDOFF              0           /* 关灯 */
#define LEDON               1           /* 开灯 *//*创建gpioled设备结构体*/
struct gpioled_dev{dev_t devid;             //设备号int major;int minor;struct cdev cdev;        //字符设备号struct class *class;     //类struct device *device;   //类下创建设备struct device_node *nd;  //设备节点int led_gpio;            //gpio编号
};
/*定义结构体变量*/
struct gpioled_dev gpioled;static int led_open(struct inode *inode, struct file *filp)
{filp->private_data=&gpioled;        //在 open 函数里面设置好私有数据以后,在 write、read、close 等函数中直接读取 private_data即可得到设备结构体return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
{int retvalue;unsigned char databuf[1];unsigned char ledstat;struct gpioled_dev *dev = filp->private_data;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];        /* 获取状态值 */if(ledstat == LEDON) { gpio_set_value(dev->led_gpio, 0);    /* 打开LED灯 */} else if(ledstat == LEDOFF) {gpio_set_value(dev->led_gpio, 1);    /* 关闭LED灯 */}return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{/*struct dtsled_dev *dev=(struct dtsled_dev*)filp->private_data;  //结构体强制转换dev->device                                                           //这样就可以通过dev进行访问私有数据里的成员变量*/return 0;
}
/*定义字符驱动操作集*/
static struct file_operations gpioled_fops = {.owner = THIS_MODULE,.open = led_open,//.read = led_read,.write = led_write,.release = led_release,};
/*驱动入口函数*/
static int __init led_init(void)
{int ret=0;            //用来接收错误/*注册字符设备驱动*/gpioled.major = 0;    //由系统分配if(gpioled.major)     //给定主设备号的情况{gpioled.devid=MKDEV(gpioled.major,0);register_chrdev_region(gpioled.devid,GPIOLED_CNT,GPIOLED_NAME);}else                 //没有给定设备号{ret=alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);   //申请设备号gpioled.major=MAJOR(gpioled.devid);    //获取分配的主设备号gpioled.minor=MINOR(gpioled.devid);    //获取分配的次设备号}if(ret<0){printk("dtsled chrdev_region error!\r\n");goto failed_devid;}printk("gpioled major=%d,minor=%d\r\n",gpioled.major,gpioled.minor);/*初始化cdev*/gpioled.cdev.owner = THIS_MODULE;/*初始化字符设备需要定义:定义字符设备,定义操作函数*/cdev_init(&gpioled.cdev,&gpioled_fops);/*添加cdev 字符设备添加进内核*/ret=cdev_add(&gpioled.cdev,gpioled.devid,GPIOLED_CNT);if(ret<0)                                                    //添加失败在goto语句里释放设备号{goto failed_cdev;}/*创建类*//*自动创建设备节点通过class和device*/gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);if (IS_ERR(gpioled.class)) {return PTR_ERR(gpioled.class);goto failed_class;}/*创建设备*/gpioled.device = device_create(gpioled.class, NULL,gpioled.devid, NULL, GPIOLED_NAME);//1.类2.父设备为NULL3.设备号4.设备使用数据一般为NULL5.设备名if (IS_ERR(gpioled.device)) {return PTR_ERR(gpioled.device);goto failed_device;}/*获取设备节点从设备树*/gpioled.nd=of_find_node_by_path("/gpioled");if(gpioled.nd==NULL) {ret=-EINVAL;goto fail_findnode;}/*获取设备树中的 gpio 属性,得到LED所使用的LED编号*/gpioled.led_gpio=of_get_named_gpio(gpioled.nd, "led-gpio", 0);if(gpioled.led_gpio < 0) {printk("can't get led-gpio");ret=-EINVAL;goto fail_findnode;}printk("led-gpio num = %d\r\n", gpioled.led_gpio);/*申请IO 如果申请失败说明IO被占用*/if(ret){printk("Failed to request the led gpio\r\n");ret=-EINVAL;goto fail_findnode;}/*使用IO 设置为输出 并且输出高电平,默认关闭LED灯*/ret = gpio_direction_output(gpioled.led_gpio, 1);if(ret < 0) {printk("can't set gpio!\r\n");goto fail_setoutput;}/*输出低电平点灯*///gpio_set_value(gpioled.led_gpio,0);return 0;
fail_setoutput:gpio_free(gpioled.led_gpio);
fail_findnode:device_destroy(gpioled.class,dtsled.devid);
failed_device:class_destroy(gpioled.class);
failed_class:cdev_del(&gpioled.cdev);
failed_cdev:unregister_chrdev_region(gpioled.devid, DTSLED_CNT);
failed_devid:return ret;//没有申请什么所以返回一个返回值不需要释放操作
}
/*驱动出口函数*/
static void __exit led_exit(void)
{/*注销字符设备驱动*/cdev_del(&gpioled.cdev);/*释放设备号*/unregister_chrdev_region(gpioled.devid,GPIOLED_CNT);/*注销设备*/device_destroy(gpioled.class, gpioled.devid);/*注销类*/class_destroy(gpioled.class);/*释放注册IO*/gpio_free(gpioled.led_gpio);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YQH");

三、makefile

KERNELDIR := /home/yqh/linux/IMX6ULL/linux_kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga
CURRENT_PATH := $(shell pwd)
obj-m :=gpioled.o
build: kernel_modules
kernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

make -j32
编译成功以后就会生成一个名为“gpioled.ko”的驱动模块文件

sudo cp gpioled.ko /home/yqh/linux/nfs/rootfs/lib/modules/4.1.15/ -f

四、应用层代码

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#define LEDOFF 0
#define LEDON 1
/*argc应用程序参数个数
*argv[]:具体的参数内容,字符串形式
*./ledAPP <filename> <0:1> 1表示关灯1表示开灯
*./ledAPP /dev/dtsled 0 关灯
*./ledAPP /dev/dtsled 1 开灯
*1执行读,在应用层打印出来读得数据 2执行写,通过调用chrdevbase_write离得打印语句而打印出来
*/
int main(int argc,char *argv[])
{int fd;int retvalue;char *filename;unsigned char databuf[1];if(argc !=3){printf("Error Usage\r\n");return -1;}filename=argv[1];fd=open(filename,O_RDWR);if(fd<0){printf("file %s open failed!\r\n",filename);return -1;}databuf[0]=atoi(argv[2]);                       //将字符转化为数字retvalue=write(fd,databuf,sizeof(databuf));if(retvalue<0){printf("LED Control Failed\r\n");//colse(fd);return -1;}retvalue=close(fd);if(retvalue<0){printf("file %s close failed!\r\n",filename);return -1;}return 0;
}

运行测试

arm-linux-gnueabihf-gcc ledApp.c -o ledApp

编译成功以后就会生成 ledApp 这个应用程序。
将编译出来的 gpioled.ko 和 ledApp 这两个文件拷贝到 rootfs/lib/modules/4.1.15目录中,重启开发板,进入到目录 lib/modules/4.1.15 中,输入如下命令加载 gpioled.ko 驱动
模块:

cd lib/modules/4.1.15/
depmod
modprobe gpioled.ko
./ledApp /dev/gpioled 1 //打开 LED 灯
./ledApp /dev/gpioled 0 //关闭 LED 灯

使用pinctrl 和 gpio 子系统的字符设备驱动相关推荐

  1. linux系统中pinctrl 和gpio子系统使用方法(教你点灯)

    如何使用pinctrl和gpio子系统点亮led pinctrl 子系统作用 设备树PIN配置 gpio子系统介绍 配置gpio相关 编写驱动程序 编写应用程序 pinctrl 子系统作用 pinct ...

  2. Linux字符设备驱动-KEY-input子系统

    使用input子系统上报按键值,按键驱动使用platform driver形式. 1.input子系统 按键.鼠标.键盘及触摸屏等都属于输入(input)设备,Linux内核为此类设备设计了input ...

  3. 【正点原子Linux连载】第四十五章 pinctrl和gpio子系统实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  4. 【正点原子MP157连载】第二十五章 pinctrl和gpio子系统实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  5. RK3399—pinctrl和gpio子系统

    1. 前言   记得以前在学习51单片机时,要控制一个GPIO输出高.低电平,就得根据对应IO寄存器每一bit的作用和含义进行配置,时钟.速率.方向.上下拉等等.51单片机是一款8位MCU,在配置寄存 ...

  6. pinctrl 和 gpio 子系统

    内容来自<[正点原子]I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf> 目录 pinctrl 子系统 pinctrl 子系统简介 I.MX6ULL 的 pinctrl 子系统 ...

  7. pinctrl和gpio子系统

    目录 1.pinctrl子系统 1)pinctrl子系统简介 2)I.MX6ULL的的pinctrl子系统驱动 3)设备树中添加pinctrl节点模板 2.gpio子系统 1)gpio子系统简介 2) ...

  8. pinctrl 和 gpio 子系统 终极总结

    1.内核提供了 pinctrl  和  gpio 子系统用于 gpio驱动.linux是一个庞大而又完善的系统  不可能 让你用裸板开发的方式 去 操作 gpio. 该系统是按照面向对象的设计思想设计 ...

  9. 以leds-gpio.c为例,浅谈device-tree、pinctrl和GPIO子系统

    一.前言 leds-gpio.c是内核源码drivers/leds/leds-gpio.c目录下的一个led驱动程序的例程(说明书位于Documentation/devicetree/bindings ...

最新文章

  1. Linux-NFS——配置过程
  2. css设置title字体_CSS中简写属性要注意TRouBLe的顺序,避免踩坑
  3. 判断是否为微信环境下打开的网页
  4. python 数据分析工具之 numpy pandas matplotlib
  5. 如何优化Hibernate EllementCollection语句
  6. 大数据学习(06)-- 云数据库
  7. mmdetection多类目标训练查看单类准确率(AP)以及使用模型测试看结果(show)
  8. 智慧林业整体解决方案_智慧农贸市场整体解决方案——前期调研篇
  9. linux根目录数量限制,windows,linux文件夹下文件上限最大个数
  10. 随心所欲学Java,起步-心理安慰
  11. Codeforces Round #467 (Div. 2)
  12. 用 ReactJs 创建Mac版的 keep
  13. Docker部署微服务应用的架构设计
  14. oracle 的数据库、表空间、表是什么关系
  15. tcl机顶盒 tk 8296刷机固件及教程
  16. SAP中的client
  17. 对Java的展望_优秀技能经验及对java学习展望
  18. 2022年8月及1-8月国内动力电池企业装车量排名:“宁王”第一,“迪王”猛追
  19. wave文件(*.wav)格式、PCM数据格式介绍
  20. mysql5_7winx64,MySQL 5.7.30 Winx64 安装

热门文章

  1. 卷积神经网络系列之卷积/池化后特征图大小怎么计算??
  2. React + Threejs + Swiper 实现全景图效果
  3. Commun. Biol. | 人工智能加速抗生素发现
  4. Machine Learning | (7) Scikit-learn的分类器算法-决策树(Decision Tree)
  5. pathview包绘制富集的kegg图
  6. ISME:胡锋/朱永官等揭示土壤噬菌体-宿主菌协同应对有机氯农药胁迫机制
  7. 推荐2个命令快速在本地和服务器之间上传下载文件
  8. MPB:林科院袁志林组-​枫香-真菌互作培养体系构建
  9. 基于R的混合线性模型的实现
  10. Nature Genetics:每年造成7亿人感染的酿脓链球菌的致病机制