Linux驱动BSP (pinctrlgpio子系统)
文章目录
- 一、pinctrl 子系统
- 1、简介
- 2、 iomuxc
- 3、怎么看设备树里面pinctrl子系统每个外设的PIN 配置
- 4、添加设备树中 pinctrl 节点模板
- 二、 gpio 子系统
- 1、设备树的体现
- 2、对于驱动开发人员,设置好设备树以后就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO
- 3、编写GPIO子系统一句话
- 三、编写测试程序实操
- 1、修改设备树,添加pinctrl&gpio子系统,并且检测系统中引脚是否复用
- 2、编写驱动程序
- 3、编译测试
- 总结
- 联系
一、pinctrl 子系统
1、简介
注册和编写不用管Linux内核调用机制,按规则编写注册就好了,大不了底层配置demo没有的需要自己配置PIN信息,其他按步就班编写就好了
作用: pinctrl 子系统主要用于管理芯片的引脚配置对应的工作模式。imx6ull 芯片拥有众多的片上外设,大多数外设需要通过芯片的引脚与外部设备(器件)相连实现相对应的控制。
- pinctrl 子系统是由芯片厂商来实现的, 简单来说用于帮助我们管理芯片引脚并自动完成引脚的初始化,而我们要做的只是在设备树中按照规定的格式写出想要的配置参数即可。
- 获取设备树中 pin 信息。
- 根据获取到的 pin 信息来设置 pin 的复用功能。
- 根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。
目的:学会在设备树下修改或者添加自己的pinctrl
2、 iomuxc
iomuxc设备节点pinctrl 子系统的平台驱动做匹配
- 子节点追加数据,不同的外设使用的 PIN 不同、其配置也不 同,意思是某个外设所使用的所有 PIN 都组织在一个子节点里面。
- 比如串口就是串口名字然后配置所有的PIN引脚信息。
- 各个厂商会提供不同的文件节点,比如正点引用在imx6ull-alientek-emmc.dts野火./arch/arm/boot/dts/imx6ull-mmc-npi.dts中通过&iomuxc追加。
3、怎么看设备树里面pinctrl子系统每个外设的PIN 配置
第一个参数为复用,具体配置是配置芯片引脚的功能,第二个参数一般为电气属性配置其上下拉等一些电气属性,一般按照官方demo配置就没有问题的
4、添加设备树中 pinctrl 节点模板
pinctrl_hog_1: hoggrp-1 {fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */>;
- 节点前缀一定要为“pinctrl_”
pinctrl_xxx: xxx
- 添加“fsl,pins”属性
fsl,pins = <>;
- 在“fsl,pins”属性中添加 PIN 配置信息
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */
MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058 /* USB_OTG1_ID */>;
二、 gpio 子系统
作用:在pinctrl设置好引脚的复用与电气属性以后,如果是使用GPIO的功能使用GPIO子系统配置引脚的输入输出,高低电平
1、设备树的体现
在需要外设使用GPIO子系统下的设备节点添加对应的gpio属性
- 比如在SD卡中检测是否插入或者拔掉的办法
- cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
&usdhc1 {pinctrl-names = "default", "state_100mhz", "state_200mhz";pinctrl-0 = <&pinctrl_usdhc1>;pinctrl-1 = <&pinctrl_usdhc1_100mhz>;pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
/* pinctrl-3 = <&pinctrl_hog_1>; */cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;keep-power-in-suspend;enable-sdio-wakeup;vmmc-supply = <®_sd1_vmmc>;status = "okay";
};
2、对于驱动开发人员,设置好设备树以后就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO
- gpio_request 函数
- gpio_free 函数
- gpio_direction_input 函数
- gpio_direction_output 函数
- gpio_get_value 函数
- gpio_set_value 函数
OF函数
- of_gpio_named_count
- of_gpio_count
- of_get_named_gpio
3、编写GPIO子系统一句话
在注册为GPIO模式下需要的节点下面添加
gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
三、编写测试程序实操
1、修改设备树,添加pinctrl&gpio子系统,并且检测系统中引脚是否复用
- 编写设备节点,在节点添加注册pinctrl子系统pinctrl_0 = <&pinctrl_gpioled>与注册GPIO子系统led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;注册完以后驱动程序就可以使用gpio注册函数编写代码了
liqi_gpioled{compatible = "liqi-led"; pinctrl_name ="default";pinctrl_0 = <&pinctrl_gpioled>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;#address-cells = <1>;#size-cells = <1>;status = "okay";};
- 在pinctrl子系统下面配置GPIO属性
pinctrl_gpioled: gpioledgrp-1 {fsl,pins = <MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0>;};
- 利用pinctrl和gpio系统引脚配置检测设备树有没有重复使用引脚的。在linux下一个引脚仅支持复用为一种功能的代码
在dts源文件下搜索GPIO1_IO03或者gpio1 3
- 设备树修改完成
2、编写驱动程序
先改设备树使用GPIO子系统gpio驱动函数,再注册设备驱动
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : gpioled.c
作者 : 左忠凯
版本 : V1.0
描述 : 采用pinctrl和gpio子系统驱动LED灯。
其他 : 无
论坛 : www.openedv.com
日志 : 初版V1.0 2019/7/13 左忠凯创建
***************************************************************/
#define GPIOLED_CNT 1 /* 设备号个数 */
#define GPIOLED_NAME "gpioled" /* 名字 */
#define LEDOFF 0 /* 关灯 */
#define LEDON 1 /* 开灯 *//* gpioled设备结构体 */
struct gpioled_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; /* led所使用的GPIO编号 */
};struct gpioled_dev gpioled; /* 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)
{filp->private_data = &gpioled; /* 设置私有数据 */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)
{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;
}/** @description : 关闭/释放设备* @param - filp : 要关闭的设备文件(文件描述符)* @return : 0 成功;其他 失败*/
static int led_release(struct inode *inode, struct file *filp)
{return 0;
}/* 设备操作函数 */
static struct file_operations gpioled_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,
};/** @description : 驱动出口函数* @param : 无* @return : 无*/
static int __init led_init(void)
{int ret = 0;/* 设置LED所使用的GPIO *//* 1、获取设备节点:gpioled */gpioled.nd = of_find_node_by_path("/gpioled");if(gpioled.nd == NULL) {printk("gpioled node not find!\r\n");return -EINVAL;} else {printk("gpioled node find!\r\n");}/* 2、 获取设备树中的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");return -EINVAL;}printk("led-gpio num = %d\r\n", gpioled.led_gpio);/* 3、设置GPIO1_IO03为输出,并且输出高电平,默认关闭LED灯 */ret = gpio_direction_output(gpioled.led_gpio, 1);if(ret < 0) {printk("can't set gpio!\r\n");}/* 注册字符设备驱动 *//* 1、创建设备号 */if (gpioled.major) { /* 定义了设备号 */gpioled.devid = MKDEV(gpioled.major, 0);register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);} else { /* 没有定义设备号 */alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME); /* 申请设备号 */gpioled.major = MAJOR(gpioled.devid); /* 获取分配号的主设备号 */gpioled.minor = MINOR(gpioled.devid); /* 获取分配号的次设备号 */}printk("gpioled major=%d,minor=%d\r\n",gpioled.major, gpioled.minor); /* 2、初始化cdev */gpioled.cdev.owner = THIS_MODULE;cdev_init(&gpioled.cdev, &gpioled_fops);/* 3、添加一个cdev */cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);/* 4、创建类 */gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);if (IS_ERR(gpioled.class)) {return PTR_ERR(gpioled.class);}/* 5、创建设备 */gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);if (IS_ERR(gpioled.device)) {return PTR_ERR(gpioled.device);}return 0;
}/** @description : 驱动出口函数* @param : 无* @return : 无*/
static void __exit led_exit(void)
{/* 注销字符设备驱动 */cdev_del(&gpioled.cdev);/* 删除cdev */unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); /* 注销设备号 */device_destroy(gpioled.class, gpioled.devid);class_destroy(gpioled.class);
}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");
3、编译测试
- 修改makefile文件
obj-m := xxx.o
make -j32
编译成功以后就会生成一个名为“gpioled.ko”的驱动模块文件。
- 编译测试 APP
arm-linux-gnueabihf-gcc xxx.c -o xxx
生成可执行文件
- gpioled.ko 和 ledApp 这两个文件拷贝到 rootfs/lib/modules/4.1.15 目 录中,重启开发板,进入到目录 lib/modules/4.1.15 中
cp xx xxx /home/alientek/linux/nfs/rootfs/lib/modules/4.1.15 -f
- 加载驱动
depmod modprobe xx.ko
查看驱动输出信息,cat /proc/devices 查看当前注册设备节点
5. 测试应用程序
./liqiledAPP dev/dtsled 1
./liqiledAPP dev/dtsled 0
- 实验现象led亮灭
总结
联系
交个博友,技术分享交流联系作者Q群:586025772
Linux驱动BSP (pinctrlgpio子系统)相关推荐
- linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现
1.概述 Gpio-keys 是基于input子系统实现的一个通用按键驱动,该驱动也符合linux驱动实现模型,即driver和device分离模型.一般按键驱动,都是基于gpio-keys进行开发的 ...
- 【linux驱动】USB子系统分析
本文针对Linux内核下USB子系统进行分析,主要会涉及一下几个方面: USB基础知识:介绍USB设备相关的基础知识 Linux USB子系统分析:分析USB系统框架,USB HCD/ROOT HUB ...
- linux驱动之I2C子系统
目录 一.I2C基本原理 二.linux内核的I2C子系统详解 1.linux内核的I2C驱动框架总览 2.I2C子系统的4个关键结构体(kernel/include/linux/i2c.h) 3.关 ...
- Linux驱动分析——I2C子系统
stm32mp157 盘古开发板 Linux内核版本4.19 目录 1.朱有鹏老师视频笔记 2.I2C子系统的4个关键结构体 3.关键文件 4.i2c-core.c初步分析 4.1.smbus代 ...
- 《Linux 驱动:输入子系统》
前言 输入子系统作为一个模块存在,向上,为用户层提供调用接口:向下,为驱动层程序提供统一的注册接口.这样,就能够使输入设备的事件通过输入子系统发送给用户层应用程序,用户层应用程序也可以通过输入子系统通 ...
- 【Linux驱动】input子系统与按键驱动
input子系统架构总览 在网上能找到一些关于input子系统架构相关的示意图,大体表达的意思都差不多. linux输入子系统(linux input subsystem)从上到下由三层实现,分别为: ...
- linux驱动之i2c子系统mpu6050设备驱动
以下是mpu6050简单的驱动实现,mpu6050是I2C接口的6轴传感器,可以作为字符设备注册到内核,本代码运行环境是3.4.2内核,4.3.2版本的编译链,12.04版本的Ubuntu,硬件环境是 ...
- 【Linux驱动】I2C子系统与触摸屏驱动
由于学习触摸屏驱动涉及到中断以及I2C相关的知识,因此先介绍一下I2C的驱动框架. 触摸屏与I2C总线的关系 关于I2C的基础概念和原理参考我的这篇博客:[裸机]嵌入式相关问题汇总(二.I2C通信概念 ...
- linux内核驱动子系统,Linux 驱动开发 / IIO子系统入门1
1. 什么是 IIO 子系统? 1.1 IIO 概述 Industrial I/O 子系统旨在为某种意义上是模数或数模转换器 (ADC,DAC) 的设备提供支持,于2009年由 Huawei 的 Jo ...
最新文章
- Python的最佳学习方式
- 二值网络训练--Training Competitive Binary Neural Networks from Scratch
- 执行计划组件、组件、老化
- 实现商城商品秒杀分析
- NoClassDefFoundError和ClassNotFoundException
- break是python合法标识符,Python笔记——break的注意事项
- 关于SQL的Group By
- Bootstrap滚动监控器
- 某IT公司的面试题,难度系数“爆表”。。。
- JAVA 使用 pdfbox实现打印 PDF 文件 (横版,竖版)
- docker搭建wekan及注册备份维护
- 产品经理的职责有哪些?到底该做什么?
- 在Python中使用Pandas.DataFrame对Excel操作笔记一 - 从Excel里面获取说需要的信息
- 什么是服务降级和熔断(网络白话摘要)
- ROM、PROM、EPROM、EEPROM、Flash ROM分别指什么?
- 计算机将文本朗读出来应用语音,你写我读_一边打字电脑将字朗读出来的软件 V1.2 最新免费版...
- java 读取pdf签名域_Java 获取PDF中的数字签名信息
- 红到发紫的人工智能,2019运势如何?
- Redis管道技术的使用
- Android Hander post与sendMessage的区别