驱动框架构建之前,需要了解以下的基础知识:
1.驱动中对gpio的操作函数有
(1)首先获取到gpio所处的设备结点,比如of_find_node_by_path。
(2)获取gpio编号,of_get_named_gpio函数,返回值是gpio的编号。
(3)请求此编号的gpio,gpio_request函数。
(4)设置gpio输入或者输出,gpio_direction_input或者。gpio_direction_output。
(5)如果是输入,通过gpio_get_value函数读取gpio的值,如果是输出,通过gpio_set_value设置gpio的值。
总结:设备结点->编号->请求编号->输入输出->值
2.gpiolib
gpio子系统就是负责管理整个框架的,gpio子系统会向应用提供一些API函数,也就是gpio_request、gpio_direction_input、gpio_direction_output等等
gpio驱动为内核源码中的/drivers/gpio中,有大量的.c文件,这些是原厂提供的,但是有几个是gpiolib.c/.h文件都是内核的gpio核心,是某些大神写的,里面含有大量对gpio的操作,有兴趣的可以去详细看看,gpiolib向应用层提供API函数,向底层提供要注册的函数,如gpiochip_add()向系统添加gpio_chip结构体。
int gpiochip_add(struct gpio_chip *chip)
{
unsigned long flags;
int status = 0;
unsigned id;
int base = chip->base;
struct gpio_desc *descs;
*
*
*
*//这个函数还有很多,有需要的请自行去查找
**
3.修改设备树
**
(1)在imx6ull-alientek-emmc.dts文件中首先在&iomuxc中添加pinctrl_gpioled: ledgrp{}
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog_1>;
imx6ul-evk {
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */
/* MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 SD1 RESET */
MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058 /* USB_OTG1_ID */
>;
};
pinctrl_gpioled : ledgrp{
fsl,pin = <
MX6UL_PAD_GPIO1_IO03__GPIO01_IO03 0X10B0
>;
}
******
******
(2)在根节点中添加gpioled{}
gpioled{
compatible = "alientek,gpioled";
pinctrl-names = "default"; //默认default
pinctrl-0 = <&pinctrl_gpioled>; //这个就是刚才我们新添加到
led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; //低点平有效
status = "okay";
};
4.make dtbs成功后,将新编译的dtb拷贝到tftpboot目录下,启动开发板。
5.cd /proc/device-tree 中可以看到刚创建的子节点gpioled
6.构建字符设备驱动框架、创建类
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#define GPIOLED_CNT 1<