Xilinx Zynq平台上通过Devicetree的Linux 4.5 GPIO中断
我使用的是一个定制开发板,带有用于运行Linux 4.5内核的Zynq XC72010。我正在为我们正在内部测试的芯片开发一个设备驱动程序,我在尝试将GPIO线路绑定到软件IRQ时遇到了很多问题。到目前为止,我已经尝试了一些方法,用尽了我能想到的谷歌搜索。我的devicetree配置的相关部分:Xilinx Zynq平台上通过Devicetree的Linux 4.5 GPIO中断,c,linux,linux-device-driver,xilinx,device-tree,C,Linux,Linux Device Driver,Xilinx,Device Tree,我使用的是一个定制开发板,带有用于运行Linux 4.5内核的Zynq XC72010。我正在为我们正在内部测试的芯片开发一个设备驱动程序,我在尝试将GPIO线路绑定到软件IRQ时遇到了很多问题。到目前为止,我已经尝试了一些方法,用尽了我能想到的谷歌搜索。我的devicetree配置的相关部分: / { compatible = "xlnx,zynq-7000"; amba { compatible = "simple-bus"; #addres
/ {
compatible = "xlnx,zynq-7000";
amba {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
ranges;
intc: interrupt-controller@f8f01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xF8F01000 0x1000>,
<0xF8F00100 0x100>;
};
i2c0: i2c@e0004000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 38>;
interrupt-parent = <&intc>;
interrupts = <0 25 4>;
reg = <0xe0004000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
// I WANT INTERRUPT TO TRIGGER
// ON THIS DEVICE (axi_gpio_0, pin 2)
device: device@48 {
compatible = "device,name";
reg = <0x48>;
reset-gpios = <&axi_gpio_0 1 0>;
interrupt-parent = <&axi_gpio_0>;
interrupt-gpios = <&axi_gpio_0 2 0>;
};
};
};
amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_gpio_0: gpio@41200000 {
#gpio-cells = <2>;
compatible = "xlnx,xps-gpio-1.00.a";
gpio-controller;
interrupt-parent = <&intc>;
interrupts = <0 31 4>;
reg = <0x41200000 0x10000>;
xlnx,all-inputs = <0x0>;
xlnx,all-inputs-2 = <0x0>;
xlnx,all-outputs = <0x0>;
xlnx,all-outputs-2 = <0x0>;
xlnx,dout-default = <0x00000000>;
xlnx,dout-default-2 = <0x00000000>;
xlnx,gpio-width = <0x10>;
xlnx,gpio2-width = <0x20>;
xlnx,interrupt-present = <0x1>;
xlnx,is-dual = <0x0>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
};
我尝试了所有这些方法和各种devicetree配置的组合,但没有一个实现了我需要的功能
方法1产生以下输出:
device: Interrupt GPIO = 892
device: IRQ = -6
device 0-0048: Failed to request IRQ: -22
device 0-0048: Found interrupt GPIO: 892
device 0-0048: IRQ Number: -6
device 0-0048: Failed to request IRQ: -22
genirq: Setting trigger mode 2 for irq 168 failed (gic_set_type+0x0/0x48)
device 0-0048: IRQ requested: 168
genirq: Setting trigger mode 8 for irq 168 failed (gic_set_type+0x0/0x48)
device 0-0048: Failed to request IRQ: -22
方法2产生以下输出:
device: Interrupt GPIO = 892
device: IRQ = -6
device 0-0048: Failed to request IRQ: -22
device 0-0048: Found interrupt GPIO: 892
device 0-0048: IRQ Number: -6
device 0-0048: Failed to request IRQ: -22
genirq: Setting trigger mode 2 for irq 168 failed (gic_set_type+0x0/0x48)
device 0-0048: IRQ requested: 168
genirq: Setting trigger mode 8 for irq 168 failed (gic_set_type+0x0/0x48)
device 0-0048: Failed to request IRQ: -22
因此,尝试使用描述符GPIO和旧的GPIO api都无法绑定中断
为了尝试方法3,我调整了devicetree:
device: device@48 {
compatible = "device,name";
reg = <0x48>;
interrupt-parent = <&axi_gpio_0>; // or <&intc>?
interrupts = <0 2 0x02>; // trying to grab pin 2
};
问题似乎是在Linux中将软件中断分配给特定的GPIO。我看不出我缺少什么。任何建议都将不胜感激
编辑1:
我发现不管出于什么原因,Linux都不喜欢低级中断。将方法3更改为:
device: device@48 {
compatible = "device,name";
reg = <0x48>;
interrupt-parent = <&axi_gpio_0>;
interrupts = <0 2 0x04>;
};
允许我成功请求IRQ。然而,我的信号是低电平,所以这对我没有多大帮助。此外,我不确定该方法是否引用axi\u gpio\u 0
引脚2作为中断信号。我可以使用intc
和axi\u gpio\u 0
作为中断父级
,它映射到相同的IRQ号(我从cat/proc/interrupts
中看到这一点)。因此,忽略信号的极性,如何确保根据axi_gpio_0
pin 2的切换触发已注册的中断
编辑2:
我跟踪了这个问题,向中断控制器的驱动程序请求一个活动的低中断:kernel/drivers/irqchip/irq gic.c
。这部分代码是导致问题的原因:
static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d);
/* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16)
return -EINVAL;
/* SPIs have restrictions on the supported types */
if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
return gic_configure_irq(gicirq, type, base, NULL);
}
允许我请求一个有效的低电平中断。出于测试目的,这应该暂时起作用
更新:
我已经成功地在GPIO引脚上创建了IRQ。我的问题是我使用的GPIO控制器。该控制器是Zynq可编程逻辑块内部的Xilinx IP块,该控制器无法触发GPIO引脚上的中断(原因我不知道)。我把我正在工作的板上的中断引脚焊接到另一个更通用的控制器上的GPIO引脚上,现在Linux和我玩得很好
总之,一个与compatible=“xlnx,xps-GPIO-1.00.a”匹配的GPIO控制器代码>无法绑定到Linux中的软件中断。如果您有此问题,请使用其他GPIO控制器
感谢大家的帮助。使用方法3的设备树节点,您应该能够使用解析的IRQ和映射的IRQ(i2c\U客户端->节点的开发,0)
检索IRQ
然后可以请求检索到的IRQ,就像您使用
devm\u request\u threaded\u IRQ()
-22是Meth 1/2的-EINVAL
(无效参数)。此外,IRQ数字应>=0,因此printk错误或IRQ数字为负数(这将匹配EINVAL,IMO)。ya-22来自请求负IRQ(gpiod_to_IRQ给我一个负数,-ENXIO)。因此,gpiod_to_irq似乎找不到我在DeviceTree中指定的GPIO的irq号属性名中断gpios
来自何处?这个名字是你编的吗?驱动程序如何检索此属性值?用于方法3的设备树节点是正确的。我认为属性中断gpios
不存在(如上述注释所示)。中断gpios
是我用来指定axi_GPIO_0的GPIO引脚的属性。我使用device->interrupt\u gpio=devm\u gpiod\u get\u optional(&i2c\u client->dev,“interrupt”,gpiod\u-IN)检索值代码>,其中device->interrupt\gpio
是我在别处定义的结构中的一个字段。感谢您的回复。你的建议奏效了,我的司机被打断了。我发现,不知什么原因,Linux不允许我注册低级或下降沿中断,但对高级或上升沿非常满意。这就是方法3中两个不同的genirq:Setting trigger mode
错误的原因。我的信号是低电平的,所以我需要找出一种方法来反转信号上的逻辑。我找到了Linux为什么在我的低电平中断下狂吠。请参见上面的编辑2。我认为ìinterrupts=
属性不正确,这导致中断注册到GIC,而不是GPIO中断控制器。它应该看起来像中断=
。