GPIO子系统实现led灯点亮流程:
1、注册字符设备驱动(手动/自动),编写应用层函数对应内核的
操作方法结构体
2、编写GPIO子系统的相关API
2.1解析设备树节点信息(可根据 名字/路径/compation)(以路径为例)
API: of_find_node_by_path
***********************************************老版**********************************************************
2.2根据设备树节点信息获取GPIO编号
API: of_get_named_gpio
2.3注册GPIO编号
API: gpio_requset
2.4设置方向为输出模式
API: gpio_direction_output
2.5设置初始管脚状态
API: gpio_get_value
2.6设置输出值
API: gpio_set_value
2.7释放GPIO编号
API: gpio_free
***********************************************老版**********************************************************
***********************************************新版*********************************************************
2.2获取并注册GPIO编号,并设置方向为输出(默认低电平LOW)
API: gpiod_get_from_of_node
2.3释放gpio编号
API: gpiod_put
***********************************************新版*********************************************************
内核文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
struct device_node *node;
struct gpio_desc *desc1;
struct gpio_desc *desc2;
struct gpio_desc *desc3;
struct timer_list mytimer;
//int gpiono;
int major;
char kbuf[128]={0};
int mycdev_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *off)
{
int ret;
if(size>sizeof(kbuf)) //size传过来的是sizeof(ubuf),如果ubuf>kbuf,那么实际长度为kbuf
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if(ret)
{
printk("copy to user failed...\n");
return -EIO;
}
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *off)
{
int ret;
if(size>sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if(ret)
{
printk("copy from user failed...\n");
return -EIO;
}
switch(kbuf[0])
{
case '0':
gpiod_set_value(desc1, 0);
break;
case '1':
gpiod_set_value(desc1, 1);
break;
case '2':
gpiod_set_value(desc2, 0);
break;
case '3':
gpiod_set_value(desc2, 1);
break;
case '4':
gpiod_set_value(desc3, 0);
break;
case '5':
gpiod_set_value(desc3, 1);
break;
}
return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
struct file_operations fops={
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.release = mycdev_close,
};
static int __init mycdev_init(void)
{
major = register_chrdev(0, "mycdev", &fops);
if(major<0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功,major=%d\n", major);
//根据路径解析设备树节点信息
node = of_find_node_by_path("/myleds");
if(node == NULL)
{
printk("of_find_node_by_path failed...\n");
return -1;
}
/*
//老版
//根据设备树结构体信息解析GPIO编号
gpiono = of_get_named_gpio(node, "led1", 0);
if(gpiono < 0)
{
printk("of_get_named_gpio failed...\n");
return -1;
}
//注册GPIO编号
ret = gpio_request(gpiono, NULL);
if(ret)
{
printk("gpio_request failed...\n");
return -1;
}
//设置当前GPIO方向为输出
gpio_direction_output(gpiono, 0);
//点灯
gpio_set_value(gpiono, 1);
*/
//新版
//led1,从设备书节点中解析和申请gpio编号,并设置方向为输出(默认低电平LOW)
desc1 = gpiod_get_from_of_node(node, "led1", 0, GPIOD_OUT_LOW, NULL);
if(IS_ERR(desc1))
{
printk("#desc1 gpiod_get_from_of_node failed...\n");
return PTR_ERR(desc1);
}
//led2,从设备书节点中解析和申请gpio编号,并设置方向为输出(默认低电平LOW)
desc2 = gpiod_get_from_of_node(node, "led2", 0, GPIOD_OUT_LOW, NULL);
if(IS_ERR(desc2))
{
printk("#desc2 gpiod_get_from_of_node failed...\n");
return PTR_ERR(desc2);
}
//led3,从设备书节点中解析和申请gpio编号,并设置方向为输出(默认低电平LOW)
desc3 = gpiod_get_from_of_node(node, "led3", 0, GPIOD_OUT_LOW, NULL);
if(IS_ERR(desc3))
{
printk("#desc3 gpiod_get_from_of_node failed...\n");
return PTR_ERR(desc3);
}
return 0;
}
static void __exit mycdev_exit(void)
{
//灭灯
//gpio_set_value(gpiono, 0);
gpiod_set_value(desc1, 0);
gpiod_set_value(desc2, 0);
gpiod_set_value(desc3, 0);
//释放申请的GPIO编号
//gpio_free(gpiono);
gpiod_put(desc1);
gpiod_put(desc2);
gpiod_put(desc3);
unregister_chrdev(major);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
测试文件
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char buf[128]={0};
int fd = open("/dev/myled", O_RDWR);
if(fd<0)
{
printf("error...\n");
exit(-1);
}
while(1)
{
printf("请输入:");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = '\0';
write(fd, buf, sizeof(buf));
}
close(fd);
return 0;
}