9.GPIO子系统

这篇具有很好参考价值的文章主要介绍了9.GPIO子系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

GPIO1节点

内核设备树新增rgb_led节点(使用gpio子系统)

常用的对外接口

头文件

of_find_node_by_path()函数

of_get_named_gpio()函数

gpio_request()函数

gpio_free()函数

gpio_direction_output()函数

gpio_direction_input()函数

gpio_get_value()函数

gpio_set_value()函数

GPIO子系统实验:IO引脚高低电平控制

修改设备树

dts_led.c文件

执行过程


GPIO1节点

gpio1: gpio@209c000 {
				// 用于和gpio子系统平台驱动做匹配,对应的驱动文件为 drivers/gpio/gpio-mxc.c
				compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
				//对照数据手册,gpio1寄存器组的起始地址即为0x209c000,第二个值表示范围
				reg = <0x209c000 0x4000>;
				//描述中断相关的内容
				interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
					         <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
				//描述初始化外设时钟
				clocks = <&clks IMX6UL_CLK_GPIO1>;
				//表明gpio1节点是一个gpio控制器
				gpio-controller;
				//表示要用2个cell描述一个 GPIO引脚
				#gpio-cells = <2>;
				//表示 gpio1 节点是个中断控制器
				interrupt-controller;
				//表示要用2个cell描述一个中断
				#interrupt-cells = <2>;
				//gpio编号转换成pin编号,如gpio子系统的0~9对应pinctrl的23~32号pin
				gpio-ranges = <&iomuxc  0 23 10>, <&iomuxc 10 17 6>,
					      <&iomuxc 16 33 16>;
};

内核设备树新增rgb_led节点(使用gpio子系统)

rgb_led{
    #address-cells = <1>;
    #size-cells = <1>;
    pinctrl-names = "default";
    compatible = "fire,rgb_led";
    pinctrl-0 = <&pinctrl_rgb_led>;
    // 以下每个属性都有一个属性值
    rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW>;
    rgb_led_green = <&gpio4 20 GPIO_ACTIVE_LOW>;
    rgb_led_blue = <&gpio4 19 GPIO_ACTIVE_LOW>;
    status = "okay";
};

rgb_led_red:自定义属性

&gpio1 4表示GPIO1_IO04

GPIO_ACTIVE_LOW表示低电平有效

常用的对外接口

头文件

#define <linux/gpio.h>
#define <linux/of_gpio.h>

of_find_node_by_path()函数

// path:设备树节点的绝对路径
// 获取指定路径节点的device_node结构体
inline struct device_node *of_find_node_by_path(const char *path)
/*
 * 返回值:
 *    成功:目标节点
 *    失败:NULL 
 */

of_get_named_gpio()函数

/*
 * np:指定的设备树节点
 * propname:GPIO属性名,比如rgb_led_red、rgb_led_green、rgb_led_blue
 * index:引脚索引值。若一个属性有多个属性值,index表示选第几个属性值,0表示第一个属性值
 */
static inline int of_get_named_gpio(struct device_node *np, const char *propname, int index);
/*
 * 返回值:
 *    成功:GPIO编号
 *    失败:负数
 */

gpio_request()函数

/*
 * 把指定的gpio引脚添加到pin_ctrl子系统管理,避免不同的外设使用同一个引脚
 * gpio:要申请的GPIO编号,就是在gpio子系统里的编号
 * label:给gpio设置个名字
 */
static inline int gpio_request(unsigned gpio, const char *label);
/* 返回值:
 *    成功:0
 *    失败:负数
 */

gpio_free()函数

/*
 * 释放在pinctrl子系统中注册的gpio编号
 * gpio:要释放的GPIO编号(pinctrl子系统的编号)
 */
static inline void gpio_free(unsigned gpio);
// 返回值:无

gpio_direction_output()函数

/*
 * gpio:要操作的GPIO编号
 * value:设置默认输出值
 */
static inline int gpio_direction_output(unsigned gpio , int value);
/*
 * 成功:0
 * 失败:负数
 */

gpio_direction_input()函数

//gpio:要操作的GPIO编号
int gpio_direction_input(unsigned gpio);
/*
 * 返回值:
 * 成功:0
 * 失败:负数
 */

gpio_get_value()函数

//gpio:要操作的GPIO编号
#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned gpio);
/*
 * 返回值:
 * 成功:GPIO的电平值(0、1)
 * 失败:负数
 */

gpio_set_value()函数

/*
 * gpio:要操作的GPIO编号
 * value:要设置的输出值
 */
#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned gpio, int value);
// 返回值:无

GPIO子系统实验:IO引脚高低电平控制

修改设备树

打开内核/arch/arm/boot/dts/imx6ull-mmc-npi.dts,在/内修改用户加入内容。

rgb_led{
    #address-cells = <1>;
    #size-cells = <1>;
    pinctrl-names = "default";
    compatible = "fire,rgb_led";
    pinctrl-0 = <&pinctrl_rgb_led>;

    // 以下每个属性都有一个属性值
    rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW>;
    rgb_led_green = <&gpio4 20 GPIO_ACTIVE_LOW>;
    rgb_led_blue = <&gpio4 19 GPIO_ACTIVE_LOW>;
    status = "okay";
};

虚拟机:

重新编译设备树:make ARCH=arm -j4 CROSS_COMPILE=arm-linux-gnueabihf- dtbs

然后拷贝到共享文件夹:sudo cp 内核/arch/arm/boot/dts/imx6ull-mmc-npi.dtb /home/couvrir/桌面/sharedir

开发板:

替代旧的二进制设备树:sudo cp /mnt/imx6ull-mmc-npi.dtb /usr/lib/linux-image-4.19.35-imx6/imx6ull-mmc-npi.dtb

同步缓冲区:sync

重启设备:sudo reboot

dts_led.c文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

#include <linux/string.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/platform_device.h>

#include <asm/mach/map.h>
#include <asm/io.h>

#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>

#define DEV_NAME        "rgb_led"
#define DEV_CNT         (1)

int rgb_led_red;
int rgb_led_green;
int rgb_led_blue;

/* 定义字符设备的设备号 */
static dev_t led_devno;
/* 定义字符设备结构体 */
static struct cdev led_chrdev;
/* 保存创建的类 */
struct class *class_led;
/* 保存创建的设备 */
struct device *device;
/* rgb_led的设备树节点结构体 */
struct device_node *rgb_led_device_node;

/* 定义led资源结构体,保存获取的节点信息以及转换后的虚拟寄存器地址 */
struct led_resource{
        struct device_node *device_node;        //rgb_led_red的设备树节点
        void __iomem *virtual_CCM_CCGR;
        void __iomem *virtual_IOMUXC_SW_MUX_CTL_PAD;
        void __iomem *virtual_IOMUXC_SW_PAD_CTL_PAD;
        void __iomem *virtual_DR;
        void __iomem *virtual_GDIR;
};

/* 定义RGB三个灯的led_resource结构体,保存获取的节点信息 */
struct led_resource led_red;
struct led_resource led_green;
struct led_resource led_blue;

static int led_chrdev_open(struct inode *inode, struct file *filp)
{
        printk("open form driver\n");
        return 0;
}

static ssize_t led_chrdev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
        int ret, error;
        unsigned int register_data = 0;         //暂存读取的寄存器数据
        unsigned char receive_data[10];         //用于保存接收到的数据
        unsigned int write_data = 0;

        if(cnt > 10)    cnt = 10;

        error = copy_from_user(receive_data, buf, cnt);
        if(error < 0)   return -1;

        ret = kstrtoint(receive_data, 16, &write_data);
        if(ret)         return -1;

        /* 设置GPIO1_04输出电平 */
        if(write_data & 0x04){
                gpio_set_value(rgb_led_red, 0);
        }else{
                gpio_set_value(rgb_led_red, 1);
        }

		/* 设置GPIO4_20输出电平 */
        if(write_data & 0x02){
                gpio_set_value(rgb_led_green, 0);
        }else{
                gpio_set_value(rgb_led_green, 1);
        }

        /* 设置GPIO4_19输出电平 */
        if(write_data & 0x01){
                gpio_set_value(rgb_led_blue, 0);
        }else{
                gpio_set_value(rgb_led_blue, 1);
        }

        return cnt;
}

static struct file_operations led_chrdev_fops = {
        .owner = THIS_MODULE,
        .open = led_chrdev_open,
        .write = led_chrdev_write,
};

static int led_probe(struct platform_device *pdv)
{
        int ret = -1;   //保存错误状态码
        unsigned int register_data = 0;

        printk(KERN_ALERT "match successed!\n");

        /* 获取rgb_led的设备树节点 */
        rgb_led_device_node = of_find_node_by_path("/rgb_led");
        if(rgb_led_device_node == NULL){
                printk(KERN_ERR "get rgb_led failed!\n");
                return -1;
        }

		/* 获取red led GPIO 引脚号 */
        rgb_led_red = of_get_named_gpio(rgb_led_device_node, "rgb_led_red", 0);
        if(rgb_led_red < 0){
                printk(KERN_ERR "rgb_led_red failed!\n");
                return -1;
        }

        /* 获取green led GPIO 引脚号 */
        rgb_led_green = of_get_named_gpio(rgb_led_device_node, "rgb_led_green", 0);
        if(rgb_led_green < 0){
                printk(KERN_ERR "rgb_led_green failed!\n");
                return -1;
        }

        /* 获取blue led GPIO 引脚号 */
        rgb_led_blue = of_get_named_gpio(rgb_led_device_node, "rgb_led_blue", 0);
        if(rgb_led_blue < 0){
                printk(KERN_ERR "rgb_led_blue failed!\n");
                return -1;
        }

        /* 设置GPIO为输出模式,并默认高电平 */
        gpio_direction_output(rgb_led_red, 1);
        gpio_direction_output(rgb_led_green, 1);
        gpio_direction_output(rgb_led_blue, 1);

        /* 第一步
         * 采用动态分配的方式获取设备编号,次设备号为0
         * 设备名称为rgb-leds,可通过命令cat /proc/devices查看
         * DEV_CNT为1,当前只申请一个设备编号
         */
        ret = alloc_chrdev_region(&led_devno, 0, DEV_CNT, DEV_NAME);
        if(ret < 0){
                printk("fail to alloc led_devno\n");
                goto alloc_err;
        }

        /* 第二步
         * 关联字符设备结构体cdev与文件操作结构体file_operations
         */
        led_chrdev.owner = THIS_MODULE;
        cdev_init(&led_chrdev, &led_chrdev_fops);

		/* 第三步
         * 添加设备到cdev_map哈希表中
         */
        ret = cdev_add(&led_chrdev, led_devno, DEV_CNT);
        if(ret < 0){
                printk("fail to add cdev\n");
                goto add_err;
        }

        /* 第四步:创建类 */
        class_led = class_create(THIS_MODULE, DEV_NAME);

        /* 第五步:创建设备 */
        device = device_create(class_led, NULL, led_devno, NULL, DEV_NAME);

        return 0;

alloc_err:
        return -1;
add_err:
        //添加设备失败时,需要注销设备号
        unregister_chrdev_region(led_devno, DEV_CNT);
        printk("error!\n");
}

static const struct of_device_id rgb_led[] = {
        {.compatible = "fire,rgb_led"},
        {/* sentinel */}
};

/* 定义平台设备结构体 */
struct platform_driver led_platform_driver = {
        .probe = led_probe,
        .driver = {
                .name = "rgb-leds-platform",
                .owner = THIS_MODULE,
                .of_match_table = rgb_led,
        }
};


static int __init led_platform_driver_init(void)
{
        int DriverState;

        DriverState = platform_driver_register(&led_platform_driver);
        printk(KERN_ALERT "DriverState is %d\n", DriverState);

        return 0;
}

static void __exit led_platform_driver_exit(void){
        /* 取消物理地址映射到虚拟地址 */
        iounmap(led_red.virtual_CCM_CCGR);
        iounmap(led_red.virtual_IOMUXC_SW_MUX_CTL_PAD);
        iounmap(led_red.virtual_IOMUXC_SW_PAD_CTL_PAD);
        iounmap(led_red.virtual_DR);
        iounmap(led_red.virtual_GDIR);

        iounmap(led_green.virtual_CCM_CCGR);
        iounmap(led_green.virtual_IOMUXC_SW_MUX_CTL_PAD);
        iounmap(led_green.virtual_IOMUXC_SW_PAD_CTL_PAD);
        iounmap(led_green.virtual_DR);
        iounmap(led_green.virtual_GDIR);

        iounmap(led_blue.virtual_CCM_CCGR);
        iounmap(led_blue.virtual_IOMUXC_SW_MUX_CTL_PAD);
        iounmap(led_blue.virtual_IOMUXC_SW_PAD_CTL_PAD);
        iounmap(led_blue.virtual_DR);
        iounmap(led_blue.virtual_GDIR);


        /* 销毁设备 */
        device_destroy(class_led, led_devno);
        /* 删除设备号 */
        cdev_del(&led_chrdev);
        /* 取消注册字符设备 */
        unregister_chrdev_region(led_devno, DEV_CNT);
        /* 销毁类 */
        class_destroy(class_led);

		platform_driver_unregister(&led_platform_driver);

        printk(KERN_ALERT "led_platform_driver exit\n");
}

module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("couvrir");
MODULE_DESCRIPTION("led module");
MODULE_ALIAS("led module");

执行过程

虚拟机:执行makemake copy。生成.ko文件。

开发板(在挂载目录下执行):

sudo insmod dts_led.ko

ls /dev/rgb_led

sudo sh -c "echo 1 > /dev/rgb_led"

sudo sh -c "echo 2 > /dev/rgb_led"

sudo sh -c "echo 4 > /dev/rgb_led"

sudo sh -c "echo 7 > /dev/rgb_led"

sudo sh -c "echo 0 > /dev/rgb_led"

sudo rmmod dts_led.ko

9.GPIO子系统,野火i.mx 6ull内核驱动进阶,单片机文章来源地址https://www.toymoban.com/news/detail-681712.html

到了这里,关于9.GPIO子系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • i.MX 6ULL 驱动开发 二十九:向 Linux 内核中添加自己编写驱动

    Linux 内核编译流程如下: 1、配置 Linux 内核。 2、编译 Linux 内核。 说明:进入 Linux 内核源码,使用 make help 参看相关配置。 1、 menuconfig 它本身是一个软件,只提供图形界面配置的一些逻辑,并不负责提供内容。 2、 menuconfig 是内核源码树的各目录下的 kconfig 提供的。 3、 m

    2023年04月10日
    浏览(75)
  • linux基础:野火i.mx 6ull上手

    root权限:echo \\\"1 4 1 7\\\" /proc/sys/kernel/printk sudo sh -c \\\"sudo echo \\\"1 4 1 7\\\"  /proc/sys/kernel/printk   第一次进入Linux系统时,会出现触摸校验提示,按提示校准5个点就可以了。 如果想重新校验,需进入root权限执行操作。 rm /etc/pointercal(删除校准文件) reboot(重启开发板) 此时就可以重新

    2024年02月13日
    浏览(85)
  • Linux驱动开发:gpio子系统

    目录 1、GPIO配置流程 2、GPIO子系统API 2.1 of_find_node_by_path 2.2 of_get_named_gpio 2.3 gpio_request 与 gpiod_get 与 gpiod_get_index 2.4 gpio_direction_input 与 gpiod_direction_input 2.5 gpio_direction_output 与 gpiod_direction_output 2.6 gpio_get_value 与 gpiod_get_value 2.7 gpio_set_value 与 gpiod_set_value 2.8  gpiod_get_from

    2024年02月12日
    浏览(50)
  • 驱动开发作业3——GPIO子系统

    作业1:在内核模块中启用定时器,定时1s,让LED1以1s为周期实现流水灯  myled.c(驱动文件)    作业2:基于GPIO子系统完成LED灯驱动的注册,并利用应用程序测试  chrdevled.c(驱动文件) test.c(测试文件)

    2024年02月16日
    浏览(38)
  • 【Linux驱动开发】011 gpio子系统

    前面我们编写了基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。本章我们就来学习一下如何借助 pinctrl 和 gpio 子系统来简化 GPIO 驱动开发。   Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,对于

    2024年02月03日
    浏览(49)
  • [驱动开发]gpio子系统及中断实现led亮灭

    编写LED灯的驱动,使用GPIO子系统,里面添加按键的中断处理 1.应用程序发送指令控制发光二极管亮灭 2.按键1按下,led1电位反转;按键2按下,led2电位反转;按键3按下,led3电位反转   

    2024年02月14日
    浏览(78)
  • Linux驱动开发之【pinctrl和gpio子系统】

    目录 一、 pinctrl和gpio子系统 1.pinctrl子系统 1.1 pinctrl子系统简介 1.2 pinctrl子系统驱动 1.3 设备树中添加pinctrl节点模版 2. gpio子系统 2.1 gpio子系统简介 2.2 gpio子系统驱动 2.3 gpio子系统API函数 2.4 设备树中添加gpio节点模板 2.5 与gpio相关的OF函数 3. 驱动程序编写 3.1 驱动入口函数 3

    2024年02月06日
    浏览(46)
  • 【Linux驱动开发】012 gpio子系统API函数

    设置好设备树以后, 在驱动程序中就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,大家各司其职,做好自己的本职工作即可。 gpio 子系统提供的常用的 API 函数有下面几个:

    2023年04月18日
    浏览(43)
  • <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动

    <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下: <Linux开发> -之-系统移植 uboot移植过程详细记录(第一部分) <Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分

    2024年02月13日
    浏览(42)
  • RK3568驱动指南|第十二篇 GPIO子系统-第128章 GPIO入门实验

    瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网

    2024年01月21日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包