中断在设备树中的使用

某个设备要使用中断, 需要在设备树中如何描述中断?

想使用中断,节点中至少有有2个属性:

interrupts // 表示要使用哪一个中断, 中断的触发类型等等。

interrupt-parent // 这个中断要接到哪一个设备去? 即父中断控制器是谁

父中断控制器有两种指定方法:

1)只有一个中断父设备

 interrupt-parent = <&父设备标号>;

 interrupts = <... ...>, <... ...>;

ethernet@20000000 {
    compatible = "davicom,dm9000";
	reg = <0x20000000 0x2 0x20000004 0x2>;
    interrupt-parent = <&gpf>; //父中断控制器为gpf
    interrupts = <7 IRQ_TYPE_EDGE_RISING>; 
    local-mac-address = [00 00 de ad be ef];
    davicom,no-eeprom;
};

2)有多个中断父设备

 interrupts-extended = <&父设备标号 .....>, <... ... ...>;

buttons {
    compatible = "jz2440_button"; 
    eint-pins  = <&gpf 0 0>, <&gpf 2 0>, <&gpg 3 0>, <&gpg 11 0>; 
    interrupts-extended = <&intc 0 0 0 3>,  
                          <&intc 0 0 2 3>,
                          <&gpg 3 3>,
                          <&gpg 11 3>;
};

 

上述的interrupts属性用多少个u32来表示?

由它的父中断控制器来描述,在父中断控制器中, 至少有2个属性:

interrupt-controller; // 表示自己是一个中断控制器

#interrupt-cells // 表示自己的子设备里应该用几个U32的数据来描述中断

例如:

gpf {
    gpio-controller;
    #gpio-cells = <0x2>;
    interrupt-controller;
    #interrupt-cells = <0x2>; //使用两个u32数据来描述中断
    phandle = <0x6>;
};

 

如何找到一个子中断节点的父中断控制器

一般在描述子中断节点中都会有一个属性interrupt-parent,由此属性描述。

如果子中断节点中没有此属性,需要查看此节点的父节点,一级一级往上直到父节点中出现interrupt-parent。

 

interrupts属性的具体含义

interrupts属性的具体含义由各自的父中断控制器来解释

s3c2440中有一个主中断控制器,一个子中断控制器,以及一个外部中断控制器(EINTPEND)。下面截取了这些中断控制器的一些图,用来说明每个bit代表哪个中断。

主中断控制器

 

中断在设备树中的使用_第1张图片

中断在设备树中的使用_第2张图片

副中断控制器

 

中断在设备树中的使用_第3张图片

外部中断控制器

 

中断在设备树中的使用_第4张图片

设备树中的ctrl_irq实际上指的就是各个中断控制器上的对应位。

 

一个例子:

    jz2440ts@5800000 {
        compatible = "jz2440,ts";
        reg = <0x58000000 0x100>;
        reg-names = "adc_ts_physical";
        <连接到副中断控制器 父中断号31 副中断中的bit9 bit10 触发类型为3>
        interrupts = <1 31 9 3>, <1 31 10 3>;
        interrupt-names = "int_ts", "int_adc_s";
        clocks = <&clocks PCLK_ADC>;
        clock-names = "adc";
    };

例子中是一个描述触摸设备的节点,节点内并没有指定interrupt-parent,我们可以使用之前提到的方法去找。实际上此节点的父中断控制器为主中断控制器。

关于interrupts属性的描述可以在linux-4.19-rc3\Documentation\devicetree\bindings\interrupt-controller\samsung,s3c24xx-irq.txt中找到。

- #interrupt-cells : Specifies the number of cells needed to encode an
  interrupt source. The value shall be 4 and interrupt descriptor shall
  have the following format:
      
      <连接的中断控制器 父中断号 中断所占位 中断触发类型>

  ctrl_num contains the controller to use:
      - 0 ... main controller
      - 1 ... sub controller
      - 2 ... second main controller on s3c2416 and s3c2450
  parent_irq contains the parent bit in the main controller and will be
             ignored in main controllers
  ctrl_irq contains the interrupt bit of the controller
  type contains the trigger type to use

结合着上述文档内的描述,我们可以知道触摸屏节点里的对应的中断是连接到副中断控制器,父中断号31,属于副中断中的bit9 bit10,触发类型为3。查看芯片手册后可知这两个中断为INT_TC,INT_ADC_S。

 

另一个例子:

ethernet@20000000 {
            compatible = "davicom,dm9000";
            reg = <0x20000000 0x2 0x20000004 0x2>;
            interrupt-parent = <&gpf>; //父中断控制器为gpf
            //中断位bit7 
            interrupts = <7 IRQ_TYPE_EDGE_RISING>;
            local-mac-address = [00 00 de ad be ef];
            davicom,no-eeprom;
        };

这是一个描述网卡的设备树节点,它的父节点为gpf。GPF是一个外部中断,关于它子节点的中断描述在linux-4.19-rc3\Documentation\devicetree\bindings\pinctrl\samsung-pinctrl.txt中找到。

- interrupt-controller: identifies the controller node as interrupt-parent.
- #interrupt-cells: the value of this property should be 2.
 - First Cell: represents the external gpio interrupt number local to the
   external gpio interrupt space of the controller.
 - Second Cell: flags to identify the type of the interrupt
   - 1 = rising edge triggered
   - 2 = falling edge triggered
   - 3 = rising and falling edge triggered
   - 4 = high level triggered
   - 8 = low level triggered
#define IRQ_TYPE_NONE		0
#define IRQ_TYPE_EDGE_RISING	1
#define IRQ_TYPE_EDGE_FALLING	2
#define IRQ_TYPE_EDGE_BOTH	(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH	4
#define IRQ_TYPE_LEVEL_LOW	8

结合文档可知,中断引脚为GPF7,使用的是EINT7,并且触摸沿是上升沿触发。

IRQ_TYPE_EDGE_RISING定义在linux-4.19-rc3\include\dt-bindings\interrupt-controller\irq.h内。

 

驱动中使用这些中断

1、对于platform_device

一个节点被转换为platform_device,如果它的设备树里指定了中断属性,那么可以从platform_device中获得“中断资源”,函数如下,可以使用下列函数获得IORESOURCE_IRQ资源,即中断号:

/**
* platform_get_resource - get a resource for a device
* @dev: platform device
* @type: resource type   // 取哪类资源?
                         // IORESOURCE_MEM、IORESOURCE_REG IORESOURCE_IRQ等
* @num: resource index   // 这类资源中的第几个
*/
struct resource *platform_get_resource(struct platform_device *dev,
              unsigned int type, unsigned int num);

2、对于i2c和spi设备节点

对于这两种设备节点,在转化的过程中,除了会处理设备树节点中各种信息,也会同时处理中断信息。

对于i2c节点:

static int i2c_device_probe(struct device *dev)
{
    struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;

 
	if (!client->irq && dev->of_node) {
		int irq = of_irq_get(dev->of_node, 0); //得到节点中的中断号
 
		if (irq == -EPROBE_DEFER)
			return irq;
		if (irq < 0)
			irq = 0;
 
		client->irq = irq;
	}
   ....
}

获取节点中的中断号保存在client->irq中

对于spi节点:

static int spi_drv_probe(struct device *dev)
{
	const struct spi_driver		*sdrv = to_spi_driver(dev->driver);
	struct spi_device		*spi = to_spi_device(dev);
	int ret;

	ret = of_clk_set_defaults(dev->of_node, false);
	if (ret)
		return ret;

	if (dev->of_node) {
		spi->irq = of_irq_get(dev->of_node, 0); //获取设备树中的中断号
		if (spi->irq == -EPROBE_DEFER)
			return -EPROBE_DEFER;
		if (spi->irq < 0)
			spi->irq = 0;
	}

	ret = dev_pm_domain_attach(dev, true);
	if (ret)
		return ret;

	ret = sdrv->probe(spi);
	if (ret)
		dev_pm_domain_detach(dev, true);

	return ret;
}

驱动程序可直接在probe函数中直接使用这些中断。

GPIO中断使用方法

假如使用的中断对应接到了io上,则可以使用此方法定义和使用中断。

首先在设备树中定义一个io

device{
	   ...
       irq-gpio = <&gpio4 21 1>; //声明使用的引脚
       ..
	};

在驱动代码中获取中断

irq_gpio = of_get_named_gpio ( np, "irq-gpio", 0 ); //获取属性irq-gpio的引脚
if ( irq_gpio < 0 )
{
	ret = irq_gpio;
	if ( ret != -ENOENT )
	{
		if ( ret != -EPROBE_DEFER )
			dev_err ( dev,
					  "Failed to get gpio flags, error: %d\n",
					  ret );
		return  ret ;
	}
}

irq  = gpiod_to_irq ( gpio_to_desc ( irq_gpio ) ); // 获取中断号
if ( irq < 0 )
{
	ret = irq;
	dev_err ( dev,
			  "Unable to get irq number for GPIO %d, error %d\n",
			  irq_gpio, ret );
	return ret;
}

之后即可使用此中断号去申请中断。

你可能感兴趣的:(设备树)