本文主旨在于介绍gpio功能的使用,故不会去细剖pinctrl中的代码框架;为了介绍gpio在全志平台的使用,分为三个部分,uboot中的gpio使用,内核中的gpio使用,内核中的pinctrl使用以及debug;
并附上简单的demo驱动,方便驱动工程师快速使用全志平台进行gpio相关的驱动开发;
对于gpio的操作,封装在include/sys_config.h,用户可在查阅其他驱动(如显示屏)借鉴完成所需的代码;以下是uboot中实现gpio_led的量灭简单demo;
gpio_led.c
1 |
|
gpio_led.h
1 | #ifndef __GPIO_LED_H |
调用接口流程:
1 | --- a/u-boot-2014.07/board/sunxi/common/secondary_main.c |
如果在uboot中调用了gpio设置方向,那么内核中probe就不必去调用gpio_direction_output(led_red,0),这样才不会导致uboot中设置的电源状态被修改;
对于驱动工程师,使用gpio驱动是件无法逃避的一件事情,gpio的常见操作包括,输入输出,驱动能力,上下拉,电平;
一:添加所要申请的gpio
方法一:sys_config.fex添加对应的描述
pmu_type_c_sel = port:PH10<1><default><default><0>
方法二:dts的配置方法
pmu_type_c_sel=<&pio PH 10 1 1 1 0>; | | | | | | | |-------------------电平 | | | | | | |----------------------上下拉 | | | | | |-------------------------驱动力 | | | | |----------------------------复用类型,0-GPIOIN 1-GPIOOUT.. | | | |------------------------------pin bank内偏移. | | |---------------------------------哪个bank | |--------------------------------------指向哪个pio,属于cpus要用&r_pio |-----------------------------------------------------属性名字,相当sys_config子键名
二:获取相关的gpio端口
chg_dev->pmu_type_c_sel.gpio = of_get_named_gpio(pdev->dev.of_node, "pmu_type_c_sel", 0);if (!gpio_is_valid(chg_dev->pmu_type_c_sel.gpio)) { pr_err("get pmu_type_c_sel failed\n");} else { ret = gpio_request( chg_dev->pmu_type_c_sel.gpio, "pmu_type_c_sel"); if (ret != 0) { pr_err("ERR: pmu_type_c_sel request failed\n"); return -EINVAL; } ret = gpio_direction_output(chg_dev->pmu_type_c_sel.gpio, 0); if (ret < 0) { pr_err("can't request output direction pmu_type_c_sel %d\n", chg_dev->pmu_type_c_sel.gpio); return ret; } }
三:根据需求设置相关的电平
static int bmu1760_set_sel_mode(struct axp_charger_dev *cdev, int mode){ if (mode) { gpio_set_value(cdev->pmu_type_c_sel.gpio, 1); } else { gpio_set_value(cdev->pmu_type_c_sel.gpio, 0); } AXP_DEBUG(AXP_SPLY, cdev->chip->pmu_num, "set_sel_mode = %x\n", mode); return 0;}
四:设置管脚的驱动能力
正常以上三个步骤已经满足基本需求,但如果对管脚的驱动能力不满意;以下对PL管脚进行设置
DTS设置如下:gpio_led_led = <&r_pio PL 10 1 1 3 0>--- a/drivers/misc/sunxi-rf/sunxi-wlan.c+++ b/drivers/misc/sunxi-rf/sunxi-wlan.c@@ -367,6 +367,8 @@ static int sunxi_wlan_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sunxi_wlan_platdata *data; struct gpio_config config;+ unsigned long drv_level;+ char pin_name[SUNXI_PIN_NAME_MAX_LEN]; u32 val; const char *power, *io_regulator; int ret = 0;@@ -439,6 +441,14 @@ static int sunxi_wlan_probe(struct platform_device *pdev) data->gpio_wlan_regon); return ret; } + printk("%s %d\n",__func__,__LINE__);+ sunxi_gpio_to_name(config.gpio, pin_name);+ if (config.drv_level != GPIO_DRVLVL_DEFAULT) {+ printk("%s %d\n",__func__,__LINE__);+ drv_level = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, config.drv_level);+ pin_config_set(SUNXI_R_PINCTRL, pin_name, drv_level);+ }+ }
如果使用pinctrl的设置方式的话,pinctrl会为我们初始化好设置的东西,GPIO的设置方式则需要手动配置;
讲完输出以及电平的设置,另外一个管脚常用的功能中断的申请步骤这里也顺便讲一下
dts配置如下 pmu_acin_det = <&pio PH 10 0 1 1 0>chg_dev->axp_acin_det.gpio = of_get_named_gpio(pdev->dev.of_node, "pmu_acin_det_gpio", 0);if (!gpio_is_valid(chg_dev->axp_acin_det.gpio)) { pr_err("ERR: get pmu_acin_det_gpio is fail\n"); return -EINVAL;} ret = gpio_request( chg_dev->axp_acin_det.gpio, "pmu_acin_det_gpio"); if (ret != 0) { pr_err("ERR: pmu_acin_det gpio_request failed\n"); return -EINVAL;}id_irq_num = gpio_to_irq(chg_dev->axp_acin_det.gpio);if (IS_ERR_VALUE((unsigned long)id_irq_num)) { pr_err("ERR: map pmu_acin_det gpio to virq failed, err %d\n", id_irq_num); return -EINVAL;}ret = request_irq(id_irq_num, axp_acin_gpio_isr, irq_flags, "pmu_acin_det_gpio", chg_dev);if (IS_ERR_VALUE((unsigned long)ret)) { pr_err("ERR: request pmu_acin_det virq %d failed, err %d\n", id_irq_num, ret); return -EINVAL;}
gpio需要在休眠时唤醒系统:
全志目前的话只支持小cpu的gpio口唤醒系统,如果要唤醒系统,需要加入这两个步骤一:enable_gpio_wakeup_src(data->gpio_wlan_hostwake);二:request_irq的时候需要加入标志位 IRQF_NO_SUSPEND
讲完使用的步骤,我们讲下GPIO的函数调用流程,顺便带出pinctrl
gpio_set_value __gpio_set_value gpiod_set_raw_value _gpiod_set_raw_value chip->set(chip, gpio_chip_hwgpio(desc), value); sunxi_pinctrl_gpio_set writel(regval, pctl->membase + reg);
从以上流程可知,GPIO的API是建立在pinctrl之上的接口,其他流程也类似,不在赘述,开始讲pinctrl
从上面的gpio的调用流程我们可以看到gpio类似于pinctrl的client或者consumer;但对于管脚,其不止有gpio的基本功能,输入输出;当gpio组合的时候,配合芯片的控制器,他可以作为IIC,SPI的控制引脚;
管理系统中所有的可以控制的pin,在系统初始化的时候,枚举所有可以控制的pin,并标识这些pin.
管理这些pin的复用(Multiplexing),对于SOC而言,其引脚除了配置成普通的GPIO之外,若干个引脚还可以组成一个pin group,行程特定的功能。pin control subsystem需管理所有的pin group。
配置这些pin的特性,例如使能或关闭引脚上的pull-up,pull-down电阻,配置引脚的driver strength;
1 | static int ir_tx_request_gpio(struct sunxi_ir_tx_data *ir_tx_data) |
#参考资料
联系客服