本文转载自:http://blog.csdn.net/keleming1/article/details/51034766

转http://www.360doc.com/content/14/1227/18/14351252_436191812.shtml

目录

[隐藏

简介

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

RK3288 有 9 组 GPIO bank: GPIO0,GPIO1, ..., GPIO8。每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分(不是所有 bank 都有全部编号,例如 GPIO5 就只有 B0~B7, C0~C3)。

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

  • spi0_clk
  • ts0_data4
  • uart4exp_ctsn

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

RK3288 的 GPIO 驱动是在以下 pinctrl 文件中实现的:

  1. kernel/drivers/pinctrl/pinctrl-rockchip.c

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

使用

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

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

另外,扩展槽上引出了几个空闲的 GPIO 口,分别是:

这几个 GPIO 口可以自定义作输入、输出使用。

输入输出

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

首先需要在 dts (Device Tree) 文件 firefly-rk3288.dts (0930版) 或 firefly-rk3288_beta.dts (0809版) 中增加驱动的资源描述:

    1. firefly-led{
    1. compatible = "firefly,led";
    1. led-work = <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
    1. led-power = <&gpio8 GPIO_A1 GPIO_ACTIVE_LOW>;
    1. status = "okay";
    1. };

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

  1. led-work GPIO8_A2 GPIO_ACTIVE_LOW
  2. led-power GPIO8_A1 GPIO_ACTIVE_LOW

GPIO_ACTIVE_LOW 表示低电平有效(灯亮),如果是高电平有效,需要替换为 GPIO_ACTIVE_HIGH 。

之后在驱动程序中加入对 GPIO 口的申请和控制则可:

  1. #ifdef CONFIG_OF
  2. #include <linux/of.h>
  3. #include <linux/of_gpio.h>
  4. #endif
  5.  
  6. static int firefly_led_probe(struct platform_device *pdev)
  7. {
  8. int ret = -1;
  9. int gpio, flag;
  10. struct device_node *led_node = pdev->dev.of_node;
  11.  
  12. gpio = of_get_named_gpio_flags(led_node, "led-power", 0, &flag);
  13. if (!gpio_is_valid(gpio)){
  14. printk("invalid led-power: %d\n",gpio);
  15. return -1;
  16. }
  17. if (gpio_request(gpio, "led_power")) {
  18. printk("gpio %d request failed!\n",gpio);
  19. return ret;
  20. }
  21. led_info.power_gpio = gpio;
  22. led_info.power_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
  23. gpio_direction_output(led_info.power_gpio, !(led_info.power_enable_value));
  24. ...
  25. on_error:
  26. gpio_free(gpio);
  27. }

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,需要先设置成输入模式,然后再读取值:

  1. int val;
  2. gpio_direction_input(your_gpio);
  3. val = gpio_get_value(your_gpio);

下面是常用的 GPIO API 定义:

  1. #include <linux/gpio.h>
  2. #include <linux/of_gpio.h>
  3.  
  4. enum of_gpio_flags {
  5. OF_GPIO_ACTIVE_LOW = 0x1,
  6. };
  7.  
  8. int of_get_named_gpio_flags(struct device_node *np, const char *propname,
  9. int index, enum of_gpio_flags *flags);
  10.  
  11. int gpio_is_valid(int gpio);
  12.  
  13. int gpio_request(unsigned gpio, const char *label);
  14.  
  15. void gpio_free(unsigned gpio);
  16.  
  17. int gpio_direction_input(int gpio);
  18.  
  19. int gpio_direction_output(int gpio, int v)

复用

如何定义 GPIO 有哪些功能可以复用,在运行时又如何切换功能呢?以 I2C4 为例作简单的介绍。

查规格表可知,I2C4_SDA 与 GPIO7C1 的功能定义如下:

Pad# func0 func1
I2C4_SDA/GPIO7_C1 gpio7c1 i2c4tp_sda
I2C4_SCL/GPIO7_C2 gpio7c2 i2c4tp_scl

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

  1. i2c4: i2c@ff160000 {
  2. compatible = "rockchip,rk30-i2c";
  3. reg = <0xff160000 0x1000>;
  4. interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
  5. #address-cells = <1>;
  6. #size-cells = <0>;
  7. pinctrl-names = "default", "gpio";
  8. pinctrl-0 = <&i2c4_sda &i2c4_scl>;
  9. pinctrl-1 = <&i2c4_gpio>;
  10. gpios = <&gpio7 GPIO_C1 GPIO_ACTIVE_LOW>, <&gpio7 GPIO_C2 GPIO_ACTIVE_LOW>;
  11. clocks = <&clk_gates6 15>;
  12. rockchip,check-idle = <1>;
  13. status = "disabled";
  14. };

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

  • pinctrl-names 定义了状态名称列表: default (i2c 功能) 和 gpio 两种状态。
  • pinctrl-0 定义了状态 0 (即 default)时需要设置的 pinctrl: i2c4_sda 和 i2c4_scl
  • pinctrl-1 定义了状态 1 (即 gpio)时需要设置的 pinctrl: i2c4_gpio

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

  1. / {
  2. pinctrl: pinctrl@ff770000 {
  3. compatible = "rockchip,rk3288-pinctrl";
  4. ...
  5. gpio7_i2c4 {
  6. i2c4_sda:i2c4-sda {
  7. rockchip,pins = <I2C4TP_SDA>;
  8. rockchip,pull = <VALUE_PULL_DISABLE>;
  9. rockchip,drive = <VALUE_DRV_DEFAULT>;
  10. //rockchip,tristate = <VALUE_TRI_DEFAULT>;
  11. };
  12.  
  13. i2c4_scl:i2c4-scl {
  14. rockchip,pins = <I2C4TP_SCL>;
  15. rockchip,pull = <VALUE_PULL_DISABLE>;
  16. rockchip,drive = <VALUE_DRV_DEFAULT>;
  17. //rockchip,tristate = <VALUE_TRI_DEFAULT>;
  18. };
  19.  
  20. i2c4_gpio: i2c4-gpio {
  21. rockchip,pins = <FUNC_TO_GPIO(I2C4TP_SDA)>, <FUNC_TO_GPIO(I2C4TP_SCL)>;
  22. rockchip,drive = <VALUE_DRV_DEFAULT>;
  23. };
  24. };
  25. ...
  26. }
  27. }

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

  1. #define GPIO7_C1 0x7c10
  2. #define I2C4TP_SDA 0x7c11
  3.  
  4. #define GPIO7_C2 0x7c20
  5. #define I2C4TP_SCL 0x7c21

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

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

也就是说 FUNC_TO_GPIO(I2C4TP_SDA) == GPIO7_C1, FUNC_TO_GPIO(I2C4TP_SCL) == GPIO7_C2 。

像 0x7c11 这样的值是有编码规则的:

  1. 7 c1 1
  2. | | `- func
  3. | `---- offset
  4. `------ bank
  5. 0x7c11 就表示 GPIO7_C1 func1, 即 i2c4tp_sda 。

在复用时,如果选择了 "default" (即 i2c 功能),系统会应用 i2c4_sda 和 i2c4_scl 这两个 pinctrl,最终得将 GPIO7_C1 和 GPIO7_C2 两个针脚切换成对应的 i2c 功能;而如果选择了 "gpio" ,系统会应用 i2c4_gpio 这个 pinctrl,将 GPIO7_C1 和 GPIO7_C2 两个针脚还原为 GPIO 功能。

我们看看 i2c 的驱动程序 /kernel/drivers/i2c/busses/i2c-rockchip.c 是如何切换复用功能的:

  1. static int rockchip_i2c_probe(struct platform_device *pdev)
  2. {
  3. struct rockchip_i2c *i2c = NULL;
  4. struct resource *res;
  5. struct device_node *np = pdev->dev.of_node;
  6. int ret;
  7. // ...
  8. i2c->sda_gpio = of_get_gpio(np, 0);
  9. if (!gpio_is_valid(i2c->sda_gpio)) {
  10. dev_err(&pdev->dev, "sda gpio is invalid\n");
  11. return -EINVAL;
  12. }
  13. ret = devm_gpio_request(&pdev->dev, i2c->sda_gpio, dev_name(&i2c->adap.dev));
  14. if (ret) {
  15. dev_err(&pdev->dev, "failed to request sda gpio\n");
  16. return ret;
  17. }
  18. i2c->scl_gpio = of_get_gpio(np, 1);
  19. if (!gpio_is_valid(i2c->scl_gpio)) {
  20. dev_err(&pdev->dev, "scl gpio is invalid\n");
  21. return -EINVAL;
  22. }
  23. ret = devm_gpio_request(&pdev->dev, i2c->scl_gpio, dev_name(&i2c->adap.dev));
  24. if (ret) {
  25. dev_err(&pdev->dev, "failed to request scl gpio\n");
  26. return ret;
  27. }
  28. i2c->gpio_state = pinctrl_lookup_state(i2c->dev->pins->p, "gpio");
  29. if (IS_ERR(i2c->gpio_state)) {
  30. dev_err(&pdev->dev, "no gpio pinctrl state\n");
  31. return PTR_ERR(i2c->gpio_state);
  32. }
  33. pinctrl_select_state(i2c->dev->pins->p, i2c->gpio_state);
  34. gpio_direction_input(i2c->sda_gpio);
  35. gpio_direction_input(i2c->scl_gpio);
  36. pinctrl_select_state(i2c->dev->pins->p, i2c->dev->pins->default_state);
  37. // ...
  38. }

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

  1. gpios = <&gpio7 GPIO_C1 GPIO_ACTIVE_LOW>, <&gpio7 GPIO_C2 GPIO_ACTIVE_LOW>;

然后是调用 devm_gpio_request 来申请 gpio,接着是调用 pinctrl_lookup_state 来查找 “gpio” 状态,而默认状态 "default" 已经由框架保存到 i2c->dev-pins->default_state 中了。

最后调用 pinctrl_select_state 来选择是 "default" 还是 "gpio" 功能。

下面是常用的复用 API 定义:

  1. #include <linux/pinctrl/consumer.h>
  2.  
  3. struct device {
  4. //...
  5. #ifdef CONFIG_PINCTRL
  6. struct dev_pin_info *pins;
  7. #endif
  8. //...
  9. };
  10.  
  11. struct dev_pin_info {
  12. struct pinctrl *p;
  13. struct pinctrl_state *default_state;
  14. #ifdef CONFIG_PM
  15. struct pinctrl_state *sleep_state;
  16. struct pinctrl_state *idle_state;
  17. #endif
  18. };
  19.  
  20. struct pinctrl_state * pinctrl_lookup_state(struct pinctrl *p, const char *name);
  21.  
  22. int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);

RK3288的gpio设置【转】的更多相关文章

  1. RK3288的gpio设置

    http://www.360doc.com/content/14/1227/18/14351252_436191812.shtml 目录 [隐藏]  1 简介 2 使用 2.1 输入输出 2.2 复用 ...

  2. RK3288 GPIO

    简介GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚.RK3288有9组 GPIO bank: GPIO0,G ...

  3. 关于DSP的GPIO的输入输出设置

    DSP 28335 的 GPIO的输入设置: GPIO的输入设置时,除了将此GPIO设置为输入之外,还需要将此GPIO口的电平拉高 //RXD3 GpioCtrlRegs.GPBMUX2.bit.GP ...

  4. S3C6410 GPIO操作接口

    在后面的驱动学习中,需要对GPIO进行一系列的操作,了解这些引脚操作有助于编码的效率. 一.配置GPIO S3C6410要使用其引脚时,需要对其进行配置,如配置为输入/输出/中断等功能,根据芯片手册来 ...

  5. stm32之GPIO(二)

    输入上拉:当IO口作为输入时,比如按键输入,而按键是与地连接,按下时为低电平,则没按下时该IO口应为高电平,上拉即是该IO口通过一个电阻与电源相连,则没按下时为高电平,按下即为低电平. 输入下拉:同理 ...

  6. Linux GPIO 注册和应用

    Linux GPIO 注册和应用 Linux Kernel, GPIO, ARM 于Linux kernel代码.经常使用 GPIO 作为一个特殊的信号,如芯片片选信号. GPIO 功能应用,我们经常 ...

  7. LPC1768外部中断与GPIO中断

    LPC1768的外部中断严格来说只有四个,分别是EINT0,EINT1,EINT2,EINT3,技术手册上有如下说明 控制这四个外部中断靠以下寄存器 这三个寄存器的0 1 2 3位分别代表中断的0 1 ...

  8. 什么是GPIO?

    ”通用输入/输出口”(GPIO)是一个灵活的由软件控制的数字信号.他们可由多种芯片提供,且对于从事嵌入式和定制硬件的Linux开发者来说是比较熟 悉.每个GPIO都代表一个连接到特定引脚或球栅阵列(B ...

  9. gpio口、内核定时器使用

    /*申请gpio*/ int gpio_request(unsigned gpio, const char *label); /*设置gpio为输入状态,即设置如(GPH0CON)*/ int gpi ...

随机推荐

  1. YUM:Yellow dog Updater Modified

    1. 什么是YUM YUM(全称为 Yellow dog Updater Modified) 是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器.基于RPM包管理,能够从 ...

  2. 早期创业,应该充分利用互联网产品和服务(从”皇包车”看一家全球中文车导服务平台如何选用ToB产品)

       前段时间,在搜索"皇包车"相关的资料,于是在IT桔子网站看到了"从'皇包车'看一家全球中文车导服务平台如何选用ToB产品"这篇文章.   我是非常的震撼! ...

  3. 【01】什么是AJAX

    什么是AJAX   AJAX(异步 JavaScript 和 XML)是 synchronous(英[ˈsɪŋkrənəs]) JavaScript and XML 的简称. AJAX不是一门新的编程 ...

  4. Qt笔记——2.编写多窗口程序

    所学教程网址:http://www.qter.org/portal.php?mod=view&aid=27&page=2 设置按钮文字 MainWindow::MainWindow(Q ...

  5. xtu read problem training 4 A - Moving Tables

    Moving Tables Time Limit: 2000ms Memory Limit: 65536KB This problem will be judged on ZJU. Original ...

  6. DP 简单题目练习

    ZOJ 1234 这道题目我表示也还不是特别能理解....还是太菜了T T 从后往前思考,因为只要后面有多的数在,那么C肯定是存在的,只要考虑是否把前两个数加在一起作为badness值这样两种情况来考 ...

  7. java 构造不可变类集的使用方法

    首先用到的就是Collections.unmodifiablexxx(         set.add("hello");         set.add("insert ...

  8. android 实现照相功能 照片存放在SID卡中,将照片显示在Image中

    protected static final int CAMERA_RESULT = 0; private String fileName; private Button takePhotoBn; p ...

  9. Ubuntu12.04之vi的问题

    版本:ubuntu12.04. 问题:vi不能正常使用方向键与退格键. 原因:ubuntu系统自带的 vi 不完整导致. 解决方法:安装完整的vi,sudo apt-get install vim-g ...

  10. 使用JavaMail通过QQ/126服务器服务发送邮件

    https://blog.csdn.net/yidragon88xx/article/details/53230310