迅为RK3568驱动指南GPIO子系统实战:实现动态切换引脚复用功能

描述

迅为RK3568驱动指南GPIO子系统实战:实现动态切换引脚复用功能

 

 

 

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

 

迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板

迅为电子

 

第136章 实战:实现动态切换引脚复用功能

再上一个小节中完成了GPIO子系统与pinctrl子系统相结合实验,在本章节中将更进一步,实现引脚动态切换引脚复用功能。

 

这里仍旧使用RK3568底板背面的20 pin GPIO底座的1号管脚来完成本章节要进行的动态切换引脚复用的功能,该引脚的核心板原理图内容如下所示:

迅为电子

 

 

图136-1

 

 左侧为该引脚的一些其他复用功能,在前面的章节中复用的都是GPIO功能,而本章节中将实现I2C3_SDA和GPIO两个复用功能的动态切换。

 

136.1 设备树的修改

本小节修改好的设备树以及编译好的boot.img镜像存放路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\90_gpioctrl09\01_内核镜像。

 

首先根据上图中的复用功能查看设备树中是否已经对该引脚进行了复用,在确保该引脚无任何复用之后,rk3568-evb1-ddr4-v10.dtsi设备树进行内容的添加,将根节点中的gpiol_a0修改为以下内容:

 

  my_gpio:gpio1_a0 {

      compatible = "mygpio";

      my-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;

        pinctrl-names = "mygpio_func1", "mygpio_func2";

        pinctrl-0 = <&mygpio_ctrl>;

        pinctrl-1 = <&i2c3_sda>;

    };

AI写代码

cpp

pinctrl-names 表示引脚控制器配置的名称,这里有两个值,分别对应复用1和复用2。

 

pinctrl-0 指定了与该配置相关联的引脚控制器句柄,这里为 &mygpio_ctrl,表示复用为gpio功能。

 

pinctrl-1 指定了与该配置相关联的引脚控制器句柄,这里为 &i2c3_sda,表示复用为i2c3_sda功能。

 

添加完成如下图所示:

 

 

 

图136-2

 

然后找到pinctrl节点,在节点尾部进行修改和添加,具体内容如下所示:

 

    mygpio_func1 {

        mygpio_ctrl: my-gpio-ctrl {

            rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;

        };

    };  

 

    mygpio_func2 {

        i2c3_sda: i2c3_sda {

            rockchip,pins = <1 RK_PA0 1 &pcfg_pull_none>;

        };

    };     

AI写代码

cpp

 

修改添加完成如下图所示:

 

 

 

图136-3

 

至此,关于设备树相关的修改就完成了,保存退出之后,编译内核,然后将生成的boot.img镜像烧写到开发板上即可。

 

136.2 驱动程序的编写

本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\88_gpioctrl07\02_module。

 

编写完成的gpio_api.c代码如下所示:

 

#include

#include

#include

#include

#include

#include

struct pinctrl *gpio_pinctrl;          // GPIO pinctrl 实例指针

struct pinctrl_state *func1_state;     // 功能1状态

struct pinctrl_state *func2_state;     // 功能2状态

int ret;

 

ssize_t selectmux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)

{

    unsigned long select;

    select = simple_strtoul(buf, NULL, 10);

    if (select == 1) {

        pinctrl_select_state(gpio_pinctrl, func1_state);     // 选择功能1状态

    } else if (select == 0) {

        pinctrl_select_state(gpio_pinctrl, func2_state);     // 选择功能2状态

    }

    return count;

}

DEVICE_ATTR_WO(selectmux);       // 定义可写的设备属性 selectmux

 

int pinctrl_get_and_lookstate(struct device *dev)

{

    gpio_pinctrl = pinctrl_get(dev);    // 获取GPIO pinctrl实例

    if (IS_ERR(gpio_pinctrl)) {

        printk("pinctrl_get is error\n");

        return -1;

    }

 

    func1_state = pinctrl_lookup_state(gpio_pinctrl, "mygpio_func1");    // 查找功能1状态

    if (IS_ERR(func1_state)) {

        printk("pinctrl_lookup_state is error\n");

        return -2;

    }

 

    func2_state = pinctrl_lookup_state(gpio_pinctrl, "mygpio_func2");    // 查找功能2状态

    if (IS_ERR(func2_state)) {

        printk("pinctrl_lookup_state is error\n");

        return -2;

    }

 

    return 0;

}

 

// 平台设备初始化函数

static int my_platform_probe(struct platform_device *dev)

{

    printk("This is mydriver_probe\n");

    pinctrl_get_and_lookstate(&dev->dev);     // 获取并查找GPIO pinctrl实例和状态

    device_create_file(&dev->dev, &dev_attr_selectmux);    // 在设备上创建属性件

    return 0;

}

 

// 平台设备的移除函数

static int my_platform_remove(struct platform_device *pdev)

{

    printk(KERN_INFO "my_platform_remove: Removing platform device\n");

 

    // 清理设备特定的操作

    // ...

 

    return 0;

}

 

 

const struct of_device_id of_match_table_id[]  = {

 {.compatible="mygpio"},

};

 

// 定义平台驱动结构体

static struct platform_driver my_platform_driver = {

    .probe = my_platform_probe,

    .remove = my_platform_remove,

    .driver = {

        .name = "my_platform_device",

        .owner = THIS_MODULE,

  .of_match_table =  of_match_table_id,

    },

};

 

// 模块初始化函数

static int __init my_platform_driver_init(void)

{

    int ret;

 

    // 注册平台驱动

    ret = platform_driver_register(&my_platform_driver);

    if (ret) {

        printk(KERN_ERR "Failed to register platform driver\n");

        return ret;

    }

 

    printk(KERN_INFO "my_platform_driver: Platform driver initialized\n");

 

    return 0;

}

 

// 模块退出函数

static void __exit my_platform_driver_exit(void)

{

    // 注销平台驱动

    platform_driver_unregister(&my_platform_driver);

 

    printk(KERN_INFO "my_platform_driver: Platform driver exited\n");

}

 

module_init(my_platform_driver_init);

module_exit(my_platform_driver_exit);

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("topeet");

AI写代码

cpp

 

136.3运行测试

136.3.1 编译驱动程序

在上一小节中的gpio_api.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:

 

export ARCH=arm64#设置平台架构

export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀

obj-m += gpio_api.o    #此处要和你的驱动源文件同名

KDIR :=/home/topeet/Linux/linux_sdk/kernel    #这里是你的内核目录                                                                                                                            

PWD ?= $(shell pwd)

all:

    make -C $(KDIR) M=$(PWD) modules    #make操作

clean:

    make -C $(KDIR) M=$(PWD) clean    #make clean操作

AI写代码

cpp

 

对于Makefile的内容注释已在上图添加,保存退出之后,来到存放gpio_api.c和Makefile文件目录下,如下图(图136-4)所示:

迅为电子

 

 

图136-4

 

然后使用命令“make”进行驱动的编译,编译完成如下图(图136-5)所示:

 

迅为电子

 

图136-5

 

编译完生成gpio_api.ko目标文件,如下图(图136-6)所示:

 

迅为电子

 

图136-6

 

至此驱动模块就编译成功了。

 

136.3.2 运行测试

首先需要确保当前开发板使用的内核镜像是我们在135.2小节中修改设备树后编译生成的镜像,然后

 

启动开发板,首先使用以下命令查看gpio1 RK_PA0引脚的复用功能,如下图所示:

 

cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins | grep 32

 

迅为电子

 

图136-7

 

可以看到在没有加载驱动之前,gpio1 RK_PA0引脚是没有进行复用的,然后使用以下命令进行驱动的加载,如下图(图54-5)所示:

 

insmod gpio_api.ko

 

迅为电子

 

图136-8

 

然后使用以下命令进入/sys/devices/platform/gpio1_a0/目录,其中的selectmux文件就是用来动态修改服用关系的,如下图所示:

 

cd /sys/devices/platform/gpio1_a0/

 

 

迅为电子

 

图136-9

 

当向selectmux文件写入0时表示选择功能2,也就是将该引脚复用为I2C3_SDA,当向selectmux文件写入1时表示选择功能1,也就是将该引脚复用为GPIO,这里我们先输入以下命令向selectmux文件写入1,验证GPIO的复用

 

echo 1 > selectmux

迅为电子

 

 

图136-10

 

然后重新使用使用以下命令查看gpio1 RK_PA0引脚的复用功能,如下图所示:

 

cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins | grep 32

迅为电子

 

 

图136-11

 

根据打印信息可以得到gpio1 RK_PA0已经被设置为了GPIO功能,然后输入以下命令向selectmux文件写入0,验证I2C3_SDA的复用

 

echo 0 > selectmux

迅为电子

 

 

图136-12

 

然后重新使用使用以下命令查看gpio1 RK_PA0引脚的复用功能,如下图所示:

 

cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins | grep 32

 

迅为电子

 

图136-13

 

根据打印信息可以得到gpio1 RK_PA0已经被复用为了I2C3_SDA功能,最后使用以下命令进行驱动的卸载,如下图所示:

 

rmmod gpio_api.ko

迅为电子

 

 

图136-14

 

至此,实现动态切换引脚复用功能实战就完成了。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分