Xilinx Zynq平台上的Linux 4.5 GPIO通过Devicetree中断

Xilinx Zynq平台上的Linux 4.5 GPIO通过Devicetree中断,第1张

概述我使用的是定制开发板和Zynq XC72010,用于运行 Linux 4.5内核.我正在为我们正在测试的芯片开发设备驱动程序,我在尝试将GPIO线绑定到软件IRQ时遇到很多问题.到目前为止,我已经尝试了一些方法,并且耗尽了我能想到的任何谷歌搜索.我的设备配置的相关部分: / { compatible = "xlnx,zynq-7000"; amba { compa 我使用的是定制开发板和Zynq XC72010,用于运行 Linux 4.5内核.我正在为我们正在测试的芯片开发设备驱动程序,我在尝试将GPIO线绑定到软件IRQ时遇到很多问题.到目前为止,我已经尝试了一些方法,并且耗尽了我能想到的任何谷歌搜索.我的设备配置的相关部分:

/ {    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>;    };};

我试图在’device’内的’axi_gpio_0’的引脚2上分配一个中断.

浏览谷歌产生了3种在驱动程序代码中绑定中断的常用方法:

/* Method 1 */device->interrupt_gpio = devm_gpiod_get_optional(&i2c_clIEnt->dev,"interrupt",GPIOD_IN);if(IS_ERR(device->interrupt_gpio))    return PTR_ERR(device->interrupt_gpio);printk("device: Interrupt GPIO = %d\n",desc_to_gpio(device->interrupt_gpio));irq = gpiod_to_irq(device->interrupt_gpio);printk("device: IRQ = %d\n",irq);ret = devm_request_threaded_irq(&i2c_clIEnt->dev,irq,NulL,device_irq_thread,IRQF_OnesHOT | IRQF_TRIGGER_HIGH,"device",device);if (ret != 0)    dev_err(&i2c_clIEnt->dev,"Failed to request IRQ: %d\n",ret);/* Method 2 */device->interrupt_gpio = devm_gpiod_get_optional(&i2c_clIEnt->dev,GPIOD_ASIS);if (IS_ERR(device->interrupt_gpio))    return PTR_ERR(device->interrupt_gpio);if (device->interrupt_gpio) {    dev_info(&i2c_clIEnt->dev,"Found interrupt GPIO: %d\n",desc_to_gpio(device->interrupt_gpio));    dev_info(&i2c_clIEnt->dev,"IRQ Number: %d\n",gpiod_to_irq(device->interrupt_gpio));    gpio_request(desc_to_gpio(device->interrupt_gpio),"DEVICE_INT");    // Request a GPIO pin from the driver    gpio_direction_input(desc_to_gpio(device->interrupt_gpio));           // Set GPIO as input    gpio_set_debounce(desc_to_gpio(device->interrupt_gpio),50);          // Set a 50ms debounce,adjust to your needs    gpio_export(desc_to_gpio(device->interrupt_gpio),false);                    // The GPIO will appear in /sys/class/gpio    ret = request_irq(gpiod_to_irq(device->interrupt_gpio),// requested interrupt                   (irq_handler_t) irqHandler,// pointer to handler function                   IRQF_TRIGGER_RISING,// interrupt mode flag                   "DEVICE_IRQ_HANDLER",// used in /proc/interrupts                   NulL);                       // the *dev_ID shared interrupt lines,NulL is okay    if (ret != 0) {        dev_err(&i2c_clIEnt->dev,ret);    }}else {    dev_err(&i2c_clIEnt->dev,"Failed to get interrupt GPIO pin\n");}/* Method 3 */dev_info(&i2c_clIEnt->dev,"IRQ requested: %d\n",i2c_clIEnt->irq);ret = devm_request_threaded_irq(&i2c_clIEnt->dev,i2c_clIEnt->irq,IRQF_OnesHOT | IRQF_TRIGGER_LOW,ret);

我尝试了所有这些方法和各种devicetree配置的组合,但它们都没有实现我需要的功能.

方法1导致此输出:

device: Interrupt GPIO = 892device: IRQ = -6device 0-0048: Failed to request IRQ: -22

方法2导致此输出:

device 0-0048: Found interrupt GPIO: 892device 0-0048: IRQ Number: -6device 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};

方法3导致此输出:

genirq: Setting trigger mode 2 for irq 168 Failed (gic_set_type+0x0/0x48)device 0-0048: IRQ requested: 168genirq: Setting trigger mode 8 for irq 168 Failed (gic_set_type+0x0/0x48)device 0-0048: Failed to request IRQ: -22

似乎问题是将软件中断分配给linux中的特定GPIO.我不知道我在这里缺少什么.任何建议表示赞赏.

编辑1:

我发现linux不管出于什么原因都不喜欢低级别的中断.将方法3改为:

device: device@48 {    compatible = "device,name";    reg = <0x48>;    interrupt-parent = <&axi_gpio_0>;    interrupts = <0 2 0x04>;};

和驱动程序代码:

dev_info(&i2c_clIEnt->dev,ret);

允许我成功申请IRQ.但是,我的信号是低电平的,所以这对我没什么帮助.另外,我不确定这种方法是否将axi_gpio_0引脚2作为中断信号引用.我可以使用intc和axi_gpio_0作为interrupt-parent,它映射到相同的IRQ号(我从cat / proc / interrupts看到这个).因此,忽略信号的极性,如何根据axi_gpio_0引脚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);}

黑客入侵内核根本不是我想做的事情,而是评论出来:

/* SPIs have restrictions on the supported types *//*if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&            type != IRQ_TYPE_EDGE_RISING)return -EINVAL;*/

允许我请求低电平有效的中断.出于测试目的,这应该暂时起作用.

更新:

我已经在GPIO引脚上成功创建了一个IRQ.我的问题出在我使用的GPIO控制器上.控制器是Zynq可编程逻辑模块内部的Xilinx IP模块,该控制器无法触发GPIO引脚上的中断(原因我不知道).我把电路板上的中断引脚焊接到一个不同的,更通用的控制器上的GPIO引脚上,现在linux正在和我很好地配合.

总而言之,匹配compatible =“xlnx,xps-gpio-1.00.a”的GPIO控制器;无法绑定到linux中的软件中断.如果您遇到此问题,请使用不同的GPIO控制器.

谢谢大家的帮助.

解决方法 使用方法3的设备树节点,您应该能够使用irq_of_parse_and_map(i2c_clIEnt-> dev.of_node,0)检索IRQ.

然后可以使用devm_request_threaded_irq()完成检索到的IRQ.

总结

以上是内存溢出为你收集整理的Xilinx Zynq平台上的Linux 4.5 GPIO通过Devicetree中断全部内容,希望文章能够帮你解决Xilinx Zynq平台上的Linux 4.5 GPIO通过Devicetree中断所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/1019422.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-23
下一篇2022-05-23

发表评论

登录后才能评论

评论列表(0条)

    保存