xilinx linux AXI GPIO 驱动学习

vivado工程

vivado 配置一个 AXI GPIO, 全输出,宽度为1
在这里插入图片描述

设备树解读

生成的对应pl.dtsi设备树文件如下

		axi_gpio: gpio@40020000 {
			#gpio-cells = <2>;
			clock-names = "s_axi_aclk";
			clocks = <&clkc 15>;
			compatible = "xlnx,axi-gpio-2.0", "xlnx,xps-gpio-1.00.a";
			gpio-controller ;
			reg = <0x40020000 0x10000>;
			xlnx,all-inputs = <0x0>;
			xlnx,all-inputs-2 = <0x0>;
			xlnx,all-outputs = <0x1>;
			xlnx,all-outputs-2 = <0x1>;
			xlnx,dout-default = <0x00000000>;
			xlnx,dout-default-2 = <0x00000000>;
			xlnx,gpio-width = <0x1>;
			xlnx,gpio2-width = <0x1>;
			xlnx,interrupt-present = <0x0>;
			xlnx,is-dual = <0x1>;
			xlnx,tri-default = <0xFFFFFFFF>;
			xlnx,tri-default-2 = <0xFFFFFFFF>;
		};

根据 compatible = “xlnx,xps-gpio-1.00.a” 找到内核文档 Documentaion/devicetree/bindings/gpio/gpio-xilinx.txt

关注以下部分

- #gpio-cells : Should be two or three. The first cell is the pin number,
  The second cell is used to specify channel offset:
		0 - first channel
		8 - second channel
  The third cell is optional and used to specify flags. Use the macros
  defined in include/dt-bindings/gpio/gpio.h
- gpio-controller : Marks the device node as a GPIO controller.

意思是需要至少两个参数,第一个是引脚号,第二个是用来指定通道,第三个参数可有可无,只是一个flag
而对于刚才生成的双通道axi gpio,引脚号从0开始,而第一个通道号为0,第二个为8

例如,可以这样访问

	name1-gpios = <&axi_gpio 0 0 GPIO_ACTIVE_LOW>;	
	name2-gpios = <&axi_gpio 0 8 GPIO_ACTIVE_HIGH>;

gpio驱动

先去看文档 Documentaion/gpio/consumer.txt
首先要 #include <linux/gpio/consumer.h>,定义了几个flags和重要的函数

The flags parameter is used to optionally specify a direction and initial value
for the GPIO. Values can be:
* GPIOD_IN to initialize the GPIO as input.
* GPIOD_OUT_LOW to initialize the GPIO as output with a value of 0.
* GPIOD_OUT_HIGH to initialize the GPIO as output with a value of 1.

flags 讲的就很清楚,设置flags 可以指定方向和初始值

使用GPIOs 部分解读

按照以前的理解,GPIO肯定要先初始化,再设置方向,再设置高低电平

Obtaining and Disposing GPIOs
=============================
Like many other kernel subsystems, gpiod_get() takes the
device that will use the GPIO and the function the requested GPIO is supposed to
fulfill:

	struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,
				    enum gpiod_flags flags)

也就是可以调用gpiod_get()函数来请求使用GPIO并实现某种功能
然后根据指示,通过 see Documentation/gpio/board.txt 来理解 the con_id parameter in the DeviceTree

假设有个设备树

	foo_device {
		compatible = "acme,foo";
		...
		led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
			    <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
			    <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */

		power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
	};

可以使用以下函数访问

struct gpio_desc *red, *green, *blue, *power;

red = gpiod_get_index(dev, "led", 0, GPIOD_OUT_HIGH);
green = gpiod_get_index(dev, "led", 1, GPIOD_OUT_HIGH);
blue = gpiod_get_index(dev, "led", 2, GPIOD_OUT_HIGH);

power = gpiod_get(dev, "power", GPIOD_OUT_HIGH);

但是gpiod_get()还需要其他函数搭配使用吗?继续看

Using GPIOs
===========
Setting Direction
-----------------
The first thing a driver must do with a GPIO is setting its direction. If no
direction-setting flags have been given to gpiod_get*(), this is done by
invoking one of the gpiod_direction_*() functions:

	int gpiod_direction_input(struct gpio_desc *desc)
	int gpiod_direction_output(struct gpio_desc *desc, int value)

但是这里说,如果没有在调用gpiod_get*()函数时给一个 direction-setting flags,那就需要调用gpiod_direction_*() 这两个函数之一

换句话说,如果在调用gpiod_get*()函数时给一个 direction-setting flag,就不需要设置其他函数了

所以,gpiod_get*()函数 完成了三件事:申请使用GPIO,通过flags设置了方向并初始化值

重要函数

struct gpio_desc *devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags)
很多驱动文件里在用,文档里只提到了是一个变体函数,调用关系如下

devm_gpiod_get_optional -> 
 devm_gpiod_get_index_optional -> //index为0 
  devm_gpiod_get_index -> 
   gpiod_get_index

本质就是 gpiod_get_index

因此,对于我们的设备树

	name1-gpios = <&axi_gpio 0 0 GPIO_ACTIVE_LOW>;	
	name2-gpios = <&axi_gpio 0 8 GPIO_ACTIVE_HIGH>;

可以这么用

struct i2c_client *client;
struct gpio_desc name1_gpio;
name1_gpio = devm_gpiod_get_optional(&client->dev, "name1", GPIOD_OUT_HIGH);
if(IS_ERR(name1_gpio)){
	dev_err(&client->dev, "can't get %s name1 GPIO in DT\n", "name1");
	return PTR_ERR(name1_gpio);
}

做了几件事:

  1. 寻找设备树中有没有 name1-gpios
  2. 申请GPIO使用
  3. 通过 flag 初始化方向并设置高低电平

结束语

多看内核文档,多看参考驱动代码,多理解

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值