0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

fireflyAIO-3128C主板GPIO使用简介

firefly 来源:firefly 作者:firefly 2019-12-24 08:52 次阅读

GPIO 使用

简介

GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。

AIO-3128C 有 4 组 GPIO bank: GPIO0,GPIO1, GPIO2, GPIO3。每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分。

每个 GPIO 口除了通用输入输出功能外,还可能有其它复用功能,例如 GPIO1_C2,可以复用成以下功能之一:

GPIO1_C2

SDMMC0_D0

UART2_TX

每个 GPIO 口的驱动电流、上下拉和重置后的初始状态都不尽相同,详细情况请参考《RK3128 规格书》中的 “RK3128 function IO description” 一章。

AIO-3128C 的 GPIO 驱动是在以下 pinctrl 文件中实现的:

kernel/drivers/pinctrl/pinctrl-rockchip.c

其核心是填充 GPIO bank 的方法和参数,并调用 gpiochip_add 注册到内核中。

使用

开发板有两个电源 LED 灯是 GPIO 口控制的,分别是:

从电路图上看,GPIO 口输出低电平时灯亮,高电平时灯灭。

输入输出

下面以电源 LED 灯的驱动为例,讲述如何在内核编写代码控制 GPIO 口的输出。

首先需要在 aio-3128c.dts 中增加驱动的资源描述:

firefly-led{ compatible = "firefly,led"; led-work = <&gpio1 GPIO_C6 GPIO_ACTIVE_LOW>; led-power = <&gpio1 GPIO_C7 GPIO_ACTIVE_LOW>; status = "okay"; };

这里定义了两颗 LED 灯的 GPIO 设置:

led-work GPIO1_C6 GPIO_ACTIVE_LOW led-power GPIO1_C7 GPIO_ACTIVE_LOW

GPIO_ACTIVE_LOW 表示低电平有效(灯亮),如果是高电平有效,需要替换为 GPIO_ACTIVE_HIGH 。 之后在驱动程序中加入对 GPIO 口的申请和控制则可:

#ifdef CONFIG_OF #include #include #endif static int firefly_led_probe(struct platform_device *pdev) { int ret = -1; int gpio, flag; struct device_node *led_node = pdev->dev.of_node; gpio = of_get_named_gpio_flags(led_node, "led-power", 0, &flag); if (!gpio_is_valid(gpio)){ printk("invalid led-power: %d\n",gpio); return -1; } if (gpio_request(gpio, "led_power")) { printk("gpio %d request failed!\n",gpio); return ret; } led_info.power_gpio = gpio; led_info.power_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0 : 1; gpio_direction_output(led_info.power_gpio, !(led_info.power_enable_value)); ... on_error:gpio_free(gpio); }

of_get_named_gpio_flags 从设备树中读取 led-power 的 GPIO 配置编号和标志,gpio_is_valid 判断该 GPIO 编号是否有效,gpio_request 则申请占用该 GPIO。如果初始化过程出错,需要调用 gpio_free 来释放之前申请过且成功的 GPIO 。

调用 gpio_direction_output 就可以设置输出高还是低电平,因为是 GPIO_ACTIVE_LOW ,如果要灯亮,需要写入 0 。

实际中如果要读出 GPIO,需要先设置成输入模式,然后再读取值:

int val;gpio_direction_input(your_gpio);val = gpio_get_value(your_gpio);

下面是常用的 GPIO API 定义:

#include #include enum of_gpio_flags { OF_GPIO_ACTIVE_LOW = 0x1, }; int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags); int gpio_is_valid(int gpio); int gpio_request(unsigned gpio, const char *label); void gpio_free(unsigned gpio); int gpio_direction_input(int gpio); int gpio_direction_output(int gpio, int v);

复用

如何定义 GPIO 有哪些功能可以复用,在运行时又如何切换功能呢?以 I2C1 为例作简单的介绍。查规格表可知,I2C1_SDA 与 I2C1_SCL 的功能定义如下:

在 /kernel/arch/arm/boot/dts/rk312x.dtsi 里有:

i2c1: i2c@20056000 { compatible = "rockchip,rk30-i2c"; reg = <0x20056000 0x1000>; interrupts = ;#address-cells = <1>;#size-cells = <0>; pinctrl-names = "default", "gpio"; pinctrl-0 = <&i2c1_sda &i2c1_scl>; pinctrl-1 = <&i2c1_gpio>; gpios = <&gpio0 GPIO_A3 GPIO_ACTIVE_LOW>, <&gpio0 GPIO_A2 GPIO_ACTIVE_LOW>; clocks = <&clk_gates8 5>; rockchip,check-idle = <1>; status = "disabled"; };

此处,跟复用控制相关的是 pinctrl- 开头的属性:

pinctrl-names 定义了状态名称列表: default (i2c 功能) 和 gpio 两种状态。

pinctrl-0 定义了状态 0 (即 default)时需要设置的 pinctrl: i2c1_sda 和 i2c1_scl

pinctrl-1 定义了状态 1 (即 gpio)时需要设置的 pinctrl: i2c1_gpio

这些 pinctrl 在 /kernel/arch/arm/boot/dts/rk312x-pinctrl.dtsi 中定义:

/ { pinctrl: pinctrl@20008000 { compatible = "rockchip,rk312x-pinctrl"; ... gpio0_i2c1 { i2c1_sda:i2c1-sda { rockchip,pins = ; rockchip,pull = ; }; i2c1_scl:i2c1-scl { rockchip,pins = ; rockchip,pull = ; }; i2c1_gpio: i2c1-gpio { rockchip,pins = , ; rockchip,pull = ; }; }; }

I2C1_SDA, I2C1_SCL 的定义在 /kernel/arch/arm/boot/dts/include/dt-bindings/pinctrl/rockchip-rk312x.h 中:

#define GPIO0_A3 0x0a30#define I2C1_SDA 0x0a31#define MMC1_CMD 0x0a32 #define GPIO0_A2 0x0a20#define I2C1_SCL 0x0a21

FUN_TO_GPIO 的定义在 /kernel/arch/arm/boot/dts/include/dt-bindings/pinctrl/rockchip.h 中:

#define FUNC_TO_GPIO(m) ((m) & 0xfff0)

也就是说 FUNC_TO_GPIO(I2C1_SDA) == GPIO0_A3, FUNC_TO_GPIO(I2C1_SCL) == GPIO7_A2 。 像 0x0a31 这样的值是有编码规则的:

0 a3 1 | | `- func | `---- offset `------ bank

0x0a31 就表示 GPIO0_A3 func1, 即 I2C1_SDA 。

在复用时,如果选择了 “default” (即 i2c 功能),系统会应用 i2c1_sda 和 i2c1_scl 这两个 pinctrl,最终得将 GPIO0_A3 和 GPIO0_A2 两个针脚切换成对应的 i2c 功能;而如果选择了 “gpio” ,系统会应用 i2c1_gpio 这个 pinctrl,将 GPIO0_A3 和 GPIO0_A2 两个针脚还原为 GPIO 功能。我们看看 i2c 的驱动程序 /kernel/drivers/i2c/busses/i2c-rockchip.c 是如何切换复用功能的:

static int rockchip_i2c_probe(struct platform_device *pdev){ struct rockchip_i2c *i2c = NULL; struct resource *res; struct device_node *np = pdev->dev.of_node; int ret; // ... i2c->sda_gpio = of_get_gpio(np, 0); if (!gpio_is_valid(i2c->sda_gpio)) { dev_err(&pdev->dev, "sda gpio is invalid\n"); return -EINVAL; } ret = devm_gpio_request(&pdev->dev, i2c->sda_gpio, dev_name(&i2c->adap.dev)); if (ret) { dev_err(&pdev->dev, "failed to request sda gpio\n"); return ret; } i2c->scl_gpio = of_get_gpio(np, 1); if (!gpio_is_valid(i2c->scl_gpio)) { dev_err(&pdev->dev, "scl gpio is invalid\n"); return -EINVAL; } ret = devm_gpio_request(&pdev->dev, i2c->scl_gpio, dev_name(&i2c->adap.dev)); if (ret) { dev_err(&pdev->dev, "failed to request scl gpio\n"); return ret; } i2c->gpio_state = pinctrl_lookup_state(i2c->dev->pins->p, "gpio"); if (IS_ERR(i2c->gpio_state)) { dev_err(&pdev->dev, "no gpio pinctrl state\n"); return PTR_ERR(i2c->gpio_state); } pinctrl_select_state(i2c->dev->pins->p, i2c->gpio_state); gpio_direction_input(i2c->sda_gpio); gpio_direction_input(i2c->scl_gpio); pinctrl_select_state(i2c->dev->pins->p, i2c->dev->pins->default_state); // ... }

首先是调用 of_get_gpio 取出设备树中 i2c1 结点的 gpios 属于所定义的两个 gpio:

gpios = <&gpio0 GPIO_A3 GPIO_ACTIVE_LOW>, <&gpio0 GPIO_A2 GPIO_ACTIVE_LOW>;

然后是调用 devm_gpio_request 来申请 gpio,接着是调用 pinctrl_lookup_state 来查找 “gpio” 状态,而默认状态 “default” 已经由框架保存到 i2c->dev-pins->default_state 中了。最后调用 pinctrl_select_state 来选择是 “default” 还是 “gpio” 功能。 下面是常用的复用 API 定义:

#include struct device { //... #ifdef CONFIG_PINCTRL struct dev_pin_info *pins;#endif//...}; struct dev_pin_info {struct pinctrl *p; struct pinctrl_state *default_state; #ifdef CONFIG_PMstruct pinctrl_state *sleep_state; struct pinctrl_state *idle_state;#endif}; struct pinctrl_state * pinctrl_lookup_state(struct pinctrl *p, const char *name); int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s); //... };

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

    关注

    87

    文章

    10990

    浏览量

    206738
  • 嵌入式主板
    +关注

    关注

    7

    文章

    6064

    浏览量

    34614
  • Firefly
    +关注

    关注

    2

    文章

    534

    浏览量

    6757
收藏 人收藏

    评论

    相关推荐

    超高性价比AIO-3128C开源主板

    `Firefly AIO-3128C开源主板拥有超高性价比处理核心四核ARM Cortex-A7,全面低于市面主流A7处理器的价格。主频高达1.3GHz,集成Mali-400 MP2图形处理器,内嵌2D加速器,拥有强大的图形与视频处理能力。丰富的外部扩展接口,可以直接应用
    发表于 05-16 16:27

    fireflyAIO-3399C主板GPIO简介

    GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。
    的头像 发表于 12-13 10:15 1782次阅读
    <b class='flag-5'>fireflyAIO</b>-3399C<b class='flag-5'>主板</b><b class='flag-5'>GPIO</b><b class='flag-5'>简介</b>

    fireflyAIO-3288C主板GPIO引脚简介

    GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。
    的头像 发表于 12-16 14:27 1478次阅读
    <b class='flag-5'>fireflyAIO</b>-3288C<b class='flag-5'>主板</b><b class='flag-5'>GPIO</b>引脚<b class='flag-5'>简介</b>

    fireflyAIO-3128C主板方案

    开机异常并循环重启 可能是电源电流不够,请使用电压为12V,电流为 2.5A~3A 的电源。
    的头像 发表于 12-20 10:28 730次阅读
    <b class='flag-5'>fireflyAIO-3128C</b><b class='flag-5'>主板</b>方案

    微雪电子AIO-3128C主板LED使用简介

    AIO-3128C 开发板上有 2 个 LED 灯
    的头像 发表于 12-23 16:17 2484次阅读
    微雪电子AIO-<b class='flag-5'>3128</b>C<b class='flag-5'>主板</b>LED使用<b class='flag-5'>简介</b>

    fireflyAIO-3128C主板I2C使用简介

    firefly
    的头像 发表于 12-24 08:47 778次阅读

    fireflyAIO-3128C主板ADC介绍使用

    firefly
    的头像 发表于 12-24 08:45 1211次阅读
    <b class='flag-5'>fireflyAIO-3128C</b><b class='flag-5'>主板</b>ADC介绍使用

    fireflyAIO-3128C主板简示

    背面视图
    的头像 发表于 12-24 09:02 489次阅读
    <b class='flag-5'>fireflyAIO-3128C</b><b class='flag-5'>主板</b>简示

    fireflyAIO-3128C主板定制Android固件简介

    定制 Android 固件 前言 定制 Android 固件,有两种方法: 改源码,然后编译生成固件。 在现有固件的基础上进行裁剪。 前一种方法,可以从各个层面去定制 Android,自由度大,但对编译环境和技术要求比较高,。现在介绍后一种方法,分为解包、定制和打包三个阶段。主机操作系统为 Linux,采用的工具为开源软件。 固件格式 统一固件 release_update.img,内含启动加载器 loader.img 和真正的固件数据 update.img release_update.img |- loader.img `- update.img update.img 是个复合
    的头像 发表于 12-24 09:07 1342次阅读

    fireflyAIO-3128C主板ADB使用简介

    adb,全称 Android Debug Bridge,是 Android 的命令行调试工具,可以完成多种功能,如跟踪系统日志,上传下载文件,安装应用等。
    的头像 发表于 12-24 09:41 901次阅读

    fireflyAIO-3128C主板MaskRom模式简介

    MaskRom 模式是设备变砖的最后一条防线。强行进入 MaskRom 涉及硬件操作,有一定风险,因此仅在设备进入不了 Loader 模式的情况下,方可尝试 MaskRom 模式。
    的头像 发表于 12-24 09:39 1314次阅读
    <b class='flag-5'>fireflyAIO-3128C</b><b class='flag-5'>主板</b>MaskRom模式<b class='flag-5'>简介</b>

    fireflyAIO-3128C主板升级固件介绍

    本文介绍了如何将主机上的固件文件,通过双公头USB数据线,烧录到开发板的闪存中。
    的头像 发表于 12-24 09:30 1126次阅读

    fireflyAIO-3128C主板启动模式介绍

    AIO-3128C 有灵活的启动方式。一般情况下,除非硬件损坏,AIO-3128C 开发板是不会变砖的。
    的头像 发表于 12-24 09:44 670次阅读

    fireflyAIO-3128C主板串口调试介绍

    AIO-3128C 开发板的调试串口与 TF 卡接口有信号引脚复用,因此无法同时使用,即: 使用调试串口时必须拔掉 TF 卡,而使用 TF 卡时不要连接调试串口。
    的头像 发表于 12-24 09:50 1203次阅读
    <b class='flag-5'>fireflyAIO-3128C</b><b class='flag-5'>主板</b>串口调试介绍

    fireflyAIO-3399J主板GPIO使用简介

    GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。
    的头像 发表于 12-24 11:00 2403次阅读
    <b class='flag-5'>fireflyAIO</b>-3399J<b class='flag-5'>主板</b><b class='flag-5'>GPIO</b>使用<b class='flag-5'>简介</b>