MTK平台GPIO的使用与调试

我们在LINUX外设驱动的开发与调试中,GPIO的正确使用是一门必修课,本文主要描述MTK平台GPIO的使用和调试方法。

一,DWS的配置

打开dws文件的工具 DrvGen.exe 有新和旧两种,不同平台使用的工具可能不一样,新平台大多使用新的 DrvGen.exe,两种工具只是打开的方式和界面不一样,其实GPIO的配置项两个都大同小异,本文以MT6739平台为例,使用新的 DrvGen.exe 工具。

路径在:alps\vendor\mediatek\proprietary\scripts\dct下,打开后选择左上角Pro然后open我们项目上所使用的 codegen.dws 文件,配置完成后保存即可,使用起来非常方便。

如下图:

  • EintMode:是否当作中断引脚来使用,例如GPIO3,如果选中了该模式,其它模式是不可见的。
  • Def.Mode:GPIO默认的模式,即在系统启动过程中GPIO口的模式,GPIO口启动模式是定义在文件 cust_gpio_boot.h 文件中的,例如GPIO2的启动模式就是作为普通的GPIO口来使用。
  • M0~M7:由于GPIO口是可以复用的,除了作为普通的GPIO口使用之外,还有其它用途,例如GPIO4则作为UART1RX来使用,所以勾选对应的复选模式为M2。
  • nPull En:是指GPIO是否使能上拉或下拉,只有当GPIO作为输入模式时才生效。
  • InPull SelHigh:上面只设置了是否使能上拉或下拉,但并没有指出到底是上拉还是下拉,此处勾选了就表示上拉,否则表示设置下拉,同样只有当GPIO作为输入模式时才生效。
  • Def.Dir: 设置GPIO的默认方向,是输入还是输出,都需要设置的。
  • In、Out:In和Out这两个选项暂时不知道有何用处,根据字面意思,应该是允许输入或输出的。
  • OutHigh:指示GPIO口作为普通IO输出时的电平高低。
  • VarName1:变量的名字,就是为GPIO口定义一个别名,在 Preloader 和 LK 驱动中只需要这个属性就可以操作这个GPIO,如设置输入电平的高低等。
  • SMT:是否使能斯密特触发器。
  • IES:输入使能,控制输入是否有效。

Preloader初始化:

文件:alps\vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6739\src\drivers\gpio_init.c

mt_gpio_set_default()->mt_gpio_set_default_chip()

LK初始化代:

文件:alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6739\gpio_init.c

mt_gpio_set_default()->mt_gpio_set_default_chip()

具体的初始化流程此处不作分析,有兴趣的朋友可以到上面文件中分析。

二,Kernel中配置和使用GPIO

上面讲了DWS文件的配置,在 Preloader 和 LK 中我们会对GPIO进行初始化,在Preloader 和 LK 驱动中我们会根据需要对部分GPIO进行操作,如果在 Kernel 中我们不再对某些GPIO进行初始化和操作,将继续沿用 Preloader 和 LK 的属性。

pinctrl 子系统

在内核中我们使用 pinctrl 子系统对GPIO进行初始化。

dts部分配置:

&pio {
	xxx_default: xxx_default {
	};
	
	xxx_init: xxxinit {
		pins_cmd0_dat {
			pinmux = <MT8163_PIN_142_EINT21__FUNC_GPIO142>; /*普通gpio模式*/
			slew-rate = <0>; /*0输入 1输出*/ 
			bias-disable; /*浮空 bias-pull-up = <00>上拉 bias-pull-down= <00>下拉*/
		};
		
		pins_cmd1_dat {
			pinmux = <MT8163_PIN_27_EINT5__FUNC_GPIO27>;
			slew-rate = <0>;
			bias-disable; 
		};
	};
};

&xxx {
	pinctrl-names = "xxx_default", "xxx_init";
	pinctrl-0 = <&xxx_default>;
	pinctrl-1 = <&xxx_init>;

	status = "okay";
};

在dts配置中,如果需要使用GPIO的复用功能,只需在 pinmux = <XXX> 中配置对应的复用功能即可。

如:

pinmux = <MT8163_PIN_142_EINT21__FUNC_ANT_SEL0>;

驱动中 Pinctrl API 的应用:

  • struct pinctrl *pctl = devm_pinctrl_get(&pdev->dev);

获取一个 pinctrl 句柄,参数dev是包含这个 pin 的device结构体,即xxx这个设备的device。

  • struct pinctrl_state *dc_charge_init = pinctrl_lookup_state(pctl, "dc_charge_init");

获取这个pin对应pin_state。

  • pinctrl_select_state(pctl, dc_charge_init);

设置引脚为某个stata。

GpioLib 库函数使用

使用 pinctrl 子系统我们也能对GPIO进行控制,如输入输出等,但是使用 gpiolib 库函数来控制GPIO的输入输出等更为方便,我们只需获取对应的 GPIO_NUM 即可。 

获取 GPIO_NUM:

  1. 直接定义-> #define GPIO_XXX_PIN     (GPIO84| 0x80000000)
  2. 从dts里获取

xxx-gpio = <&pio 22 0>;

node = of_find_matching_node(NULL, of_match);        //node = client->dev.of_node

gpio_num = of_get_named_gpio(node, "xxx-gpio", 0);

获取 IRQ_NUM:

  1. gpio_to_irq->irq_num = gpio_to_irq(gpio_num);
  2. 从dts里获取

interrupt-parent = <&pio>;

interrupts = <22 IRQ_TYPE_LEVEL_LOW>;

irq_num = irq_of_parse_and_map(node, 0);

获取到了 GPIO_NUM 和 IRQ_NUM 之后,我们就可以使用 gpiolib 库函数对GPIO进行操作了。

主要函数有:

static inline int gpio_request(unsigned int gpio, const char *label)

static inline void gpio_free(unsigned gpio)

static inline int gpio_direction_input(unsigned int gpio)

static inline int gpio_direction_output(unsigned int gpio, int v)

static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) //防抖

static inline int gpio_get_value(unsigned int gpio)

static inline void gpio_set_value(unsigned int gpio, int v)

static inline int gpio_to_irq(unsigned int gpio)

static inline int irq_to_gpio(unsigned int irq的)

至于上面函数的功能也非常好理解,功能基本就是函数名的字面意思,这里就不做解释了。

三,使用ADB获取/配置GPIO

  • 节点位置

在MTK平台,我们可以通过cat节点(mt_gpio)来查看对应的状态。不同的平台,该管脚对应的位置也是不同的。

需要先执行:adb root

查找节点位置:find sys/ -name "mt_gpio"            

一般位于:/sys/devices/platform/soc/1000b000.pinctrl/mt_gpio

  • 查看GPIO状态:

adb输入命令:cat ./sys/devices/platform/soc/1000b000.pinctrl/mt_gpio

  PIN: [MODE] [DIR] [DOUT] [DIN] [PULL_EN] [PULL_SEL] [IES] [SMT] [DRIVE] ( [R1] [R0] )
  0: 011110100 01
  1: 000010100 01
  2: 000111100 01
  3: 000010100 01
  4: 011100100 00
  5: 000010100 01
  6: 000100110
  ...

对应的属性基本与DWS配置项一致,这里只对 [DRIVE] ( [R1] [R0] ) 两项进行说明

[DRIVE]:驱动能力,一般可取值0~7

([R1] [R0]):当前GPIO pin的(上下拉)并联电阻的使能状态

1 0表示enable R1,disable R0

0 1表示disable R1,enable R0

1 1表示enable R1, enable R0

不打印出来,表示当前的GPIO pin不支持PUPD状况,即只有一个上拉电阻、一个下拉电阻。

通过对比上面信息我们可以看出GPIO的设置是否生效,如对应属性和驱动中设置不符,则需要检查驱动是否有疏漏,还要检查对应的GPIO是否有其他模块也使用了,我们也可以使用adb将GPIO配置成我们需要的状态,来验证此GPIO是否能配置成我们驱动中需要的状态。

  • 使用adb设置GPIO属性:

设置模式:echo mode 14 0 > mt_gpio

设置输入/输出:echo dir 14 1  > mt_gpio

输出高/:echo out 14 1 > mt_gpio

设置pullen:  echo pullen 14 1 > mt_gpio

NOTE:设置pullen时,

For pin with 2 pull resistors, $value can be 0 (R1=0, R0=0), 1 (R1=0, R0=1), 2 (R1=1, R0=0), 3 (R1=1, R0=1)

For pin with 1 pull resistor, $value can be 0 or 1

以上如有不当之处欢迎私信或底下评论给小编指导更正,非常感谢查阅!

发布了6 篇原创文章 · 获赞 29 · 访问量 1044

猜你喜欢

转载自blog.csdn.net/dthua888/article/details/104015612