文章目录
- 一、GPIO子系统
- (一)框架结构
- (二)GPIO子系统的API
- (三)gpio子系统控制LED灯的设备树
- 1. 画出硬件连接图
- 2. 找出控制器的设备树
- 3. 参考内核帮助文档
- 二、使用GPIO子系统实现流水灯
- 1. 设备树文件:
- 2. 驱动文件
一、GPIO子系统
(一)框架结构
(二)GPIO子系统的API
#include <linux/of_gpio.h>
int of_get_named_gpio(struct device_node *np,const char *propname, int index)
功能:
获取gpio号
参数:
@np:节点的指针
@propname:键
@index:下标 (键值的第几个数)
返回值:
成功返回gpio号,失败返回错误码
int gpio_request(unsigned gpio, const char *label)
功能:
申请要使用的GPIO
参数:
@gpio:gpio号(设备树中获取)
@label:名字,也可以写NULL
返回值:
成功返回0,失败返回错误码
int gpio_direction_input(unsigned gpio)
功能:将gpio的方向设置为输入
参数:
@gpio:gpio号
返回值:成功返回0,失败返回错误码
int gpio_direction_output(unsigned gpio, int value)
功能:将gpio的方向设置为输出
参数:
@gpio:gpio号
@value:默认输出电平状态 1高电平 0低电平
返回值:成功返回0,失败返回错误码
int gpio_get_value(unsigned gpio)
功能:获取管脚电平
参数:
@gpio:gpio号
返回值:返回1高电平 返回0低电平
void gpio_set_value(unsigned int gpio, int value)
功能:设置管脚电平的状态
参数:
@gpio:gpio号
@value:输出电平状态 1高电平 0低电平
返回值:无
void gpio_free(unsigned gpio)
功能:释放gpio
参数:
@gpio:gpio号
返回值:无
(三)gpio子系统控制LED灯的设备树
1. 画出硬件连接图
2. 找出控制器的设备树
目录:
linux-5.10.61/arch/arm/boot/dts/stm32mp151.dtsi
//stm32mp151.dtsi
gpioe: gpio@50006000 {
gpio-controller; //空属性,标识这个节点是gpio控制器的设备树节点
#gpio-cells = <2>; //2.对子节点成员个数修饰
reg = <0x50006000 0x400>;//控制器的地址,长度
clocks = <&rcc GPIOE>; //时钟
st,bank-name = "GPIOE"; //gpioe
status = "disabled"; //1.控制器的状态,disabled没有使能,okay使能
};
3. 参考内核帮助文档
帮助文档路径:
linux-5.10.61/Documentation/devicetree/bindings/gpio
在gpio目录下对应这不同厂商的帮助文档。
有厂商的帮助文档看厂商的帮助文档,没有就看通用的文档
myleds{
led1 = <&gpioe 10 0>; //10gpioe的第10个管脚,0默认状态
led2 = <&gpiof 10 0>; //10gpiof的第10个管脚,0默认状态
led3 = <&gpioe 8 0>; //8gpioe的第8个管脚,0默认状态
};
二、使用GPIO子系统实现流水灯
扩展版三个LED:
PE10 --- LED1
PF10 --- LED2
PE8 --- LED3
主控板三个LED:
1. 设备树文件:
stm32mp157a-fsmp1a.dts
/{
//在根节点中添加以下节点
myleds{
core_leds{
led1 = <&gpioz 5 0>;
led2 = <&gpioz 6 0>;
led3 = <&gpioz 7 0>;
};
expend_leds{
led1 = <&gpioe 10 0>;
led2 = <&gpiof 10 0>;
led3 = <&gpioe 8 0>;
};
};
2. 驱动文件
mynode.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h> //设备树文件相关头文件
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include "mynode.h"
const char *led[3]={"led1","led2","led3"};
int core_gpiono[3];
int expend_gpiono[3];
struct cdev *led_cdev;
struct class *led_class;
struct device *led_device;
int major = 0; //主设备号
int minor = 0;
dev_t led_dev_num;
int my_led_open(struct inode *inode, struct file *file){
struct device_node *core_node,*expend_node;
int i,ret;
//1. 获取节点
//core节点
core_node = of_find_node_by_path("/myleds/core_leds");
if(NULL == core_node){
pr_err("of_find_node_by_path error");
return -EINVAL;
}
//expend节点
expend_node = of_find_node_by_path("/myleds/expend_leds");
if(NULL == expend_node){
pr_err("of_find_node_by_path error");
return -EINVAL;
}
//2.获取gpio号
for(i=0;i<3;i++){
//core
core_gpiono[i] = of_get_named_gpio(core_node,led[i],0);
if(core_gpiono[i] < 0){
pr_err("of_get_named_gpio error");
return core_gpiono[i];
}
//expend
expend_gpiono[i] = of_get_named_gpio(expend_node,led[i],0);
if(expend_gpiono[i] < 0){
pr_err("of_get_named_gpio error");
return expend_gpiono[i];
}
}
//3. 申请gpio
for(i=0;i<3;i++){
ret=gpio_request(core_gpiono[i],NULL);
if(ret){
pr_err("gpio_request error");
for(i--;i>0;i--){
gpio_free(core_gpiono[i]);
}
return ret;
}
}
for(i=0;i<3;i++){
ret=gpio_request(expend_gpiono[i],NULL);
if(ret){
pr_err("gpio_request error");
for(i--;i>0;i--){
gpio_free(expend_gpiono[i]);
}
for(i=0;i<3;i++){
gpio_free(core_gpiono[i]);
}
return ret;
}
}
//4.设置方向为输出
for(i=0;i<3;i++){
ret = gpio_direction_output(core_gpiono[i], 0);
if (ret) {
pr_err("gpio_direction_output error\n");
goto err;
}
ret = gpio_direction_output(expend_gpiono[i], 0);
if (ret) {
pr_err("gpio_direction_output error\n");
goto err;
}
}
return 0;
err:
for(i=0;i<3;i++){
gpio_free(core_gpiono[i]);
gpio_free(expend_gpiono[i]);
}
return ret;
}
int my_led_close(struct inode *inode, struct file *file){
return 0;
}
long myled_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
switch(cmd){
case LED1_ON:
gpio_set_value(core_gpiono[0],1);
break;
case LED1_OFF:
gpio_set_value(core_gpiono[0],0);
break;
case LED2_ON:
gpio_set_value(core_gpiono[1],1);
break;
case LED2_OFF:
gpio_set_value(core_gpiono[1],0);
break;
case LED3_ON:
gpio_set_value(core_gpiono[2],1);
break;
case LED3_OFF:
gpio_set_value(core_gpiono[2],0);
break;
case LED4_ON:
gpio_set_value(expend_gpiono[0],1);
break;
case LED4_OFF:
gpio_set_value(expend_gpiono[0],0);
break;
case LED5_ON:
gpio_set_value(expend_gpiono[1],1);
break;
case LED5_OFF:
gpio_set_value(expend_gpiono[1],0);
break;
case LED6_ON:
gpio_set_value(expend_gpiono[2],1);
break;
case LED6_OFF:
gpio_set_value(expend_gpiono[2],0);
break;
}
return 0;
}
const struct file_operations ledfops={
.open=my_led_open,
.release=my_led_close,
.unlocked_ioctl=myled_ioctl,
};
static int __init mynode_init(void){
//分配对象
led_cdev = cdev_alloc();
if(NULL == led_cdev){ //成功返回结构体指针,失败返回NULL
pr_err("cdv_err error");
return -ENOMEM;
}
//初始化对象:部分成员初始化
cdev_init(led_cdev,&ledfops);
//申请设备号:如果major为0,则动态申请,否则就静态指定
if(major > 0){
register_chrdev_region(MKDEV(major,minor),1,"mynode");
}else if(major == 0){
alloc_chrdev_region(&led_dev_num,0,1,"mynode");
major=MAJOR(led_dev_num);
minor=MINOR(led_dev_num);
}
//注册
cdev_add(led_cdev,MKDEV(major,minor),1);
//自动创建设备节点
led_class=class_create(THIS_MODULE,"mynode");
led_device = device_create(led_class,NULL,MKDEV(major,minor),NULL,"mynode");
return 0;
}
static void __exit mynode_exit(void){
int i;
for(i=0;i<3;i++){
gpio_free(core_gpiono[i]);
gpio_free(expend_gpiono[i]);
}
device_destroy(led_class, MKDEV(major, minor));
class_destroy(led_class);
cdev_del(led_cdev);
unregister_chrdev_region(MKDEV(major, minor), 1);
kfree(led_cdev);
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
mynode.h
#ifndef __MYNODE_H__
#define __MYNODE_H__
#define LED1_ON _IOW('L',000,int)
#define LED1_OFF _IOW('L',001,int)
#define LED2_ON _IOW('L',010,int)
#define LED2_OFF _IOW('L',011,int)
#define LED3_ON _IOW('L',020,int)
#define LED3_OFF _IOW('L',021,int)
#define LED4_ON _IOW('L',100,int)
#define LED4_OFF _IOW('L',101,int)
#define LED5_ON _IOW('L',110,int)
#define LED5_OFF _IOW('L',111,int)
#define LED6_ON _IOW('L',120,int)
#define LED6_OFF _IOW('L',121,int)
#endif