1

I'm trying to setup a device tree source file for the first time on my custom platform. On the board is a NXP PCA9555 gpio expander. I'm attempting to setup node for the device and am a bit confused.

Here is where I'm at with the node in the dts file:

ioexp0: gpio-exp@21 {
        compatible = "nxp,pca9555";
        reg = <21>;

        interrupt-parent = <&gpio>;
        interrupts = <8 0>;

        gpio-controller;
        #gpio-cells = <2>;

        /*I don't understand the following two lines*/
        interrupt-controller;
        #interrupt-cells = <2>;
};

I got to this point by using the armada-388-gp.dts source as a guide.

My confusion is on what code processes the #interrupt-cells property. The bindings documentation is not very helpful at all for this chip as it doesn't say anything regarding interrupt cell interpretation.

Looking at the pca953x_irq_setup function in the source code for the pca9555 driver - I don't see anywhere that the #interrupt-cells property is handled. Is this handled in the linux interrupt handling code? I'm just confused as to how I'm suppose to know the meaning of the two interrupt cells.

pca953x_irq_setup for your convenience:

static int pca953x_irq_setup(struct pca953x_chip *chip,
                 int irq_base)
{
    struct i2c_client *client = chip->client;
    int ret, i;

    if (client->irq && irq_base != -1
            && (chip->driver_data & PCA_INT)) {
        ret = pca953x_read_regs(chip,
                    chip->regs->input, chip->irq_stat);
        if (ret)
            return ret;

        /*
         * There is no way to know which GPIO line generated the
         * interrupt.  We have to rely on the previous read for
         * this purpose.
         */
        for (i = 0; i < NBANK(chip); i++)
            chip->irq_stat[i] &= chip->reg_direction[i];
        mutex_init(&chip->irq_lock);

        ret = devm_request_threaded_irq(&client->dev,
                    client->irq,
                       NULL,
                       pca953x_irq_handler,
                       IRQF_TRIGGER_LOW | IRQF_ONESHOT |
                           IRQF_SHARED,
                       dev_name(&client->dev), chip);
        if (ret) {
            dev_err(&client->dev, "failed to request irq %d\n",
                client->irq);
            return ret;
        }

        ret =  gpiochip_irqchip_add_nested(&chip->gpio_chip,
                           &pca953x_irq_chip,
                           irq_base,
                           handle_simple_irq,
                           IRQ_TYPE_NONE);
        if (ret) {
            dev_err(&client->dev,
                "could not connect irqchip to gpiochip\n");
            return ret;
        }

        gpiochip_set_nested_irqchip(&chip->gpio_chip,
                        &pca953x_irq_chip,
                        client->irq);
    }

    return 0;
}

This is my first time working with device tree so I'm hoping it's something obvious that I'm just missing.

UPDATE:

As a clarification - I am working with kernel version 4.12-rc4 at the moment.

I now understand that I was misinterpreting some properties of the device tree. I was previously under the impression that the driver had to specify how all properties were handled. I now see that linux will actually handle many of the generic properties such as gpios or interrupts (which makes a lot of sense).

Here is a bit more of a detailed explanation of how the translation from intspec to IRQ_TYPE* happens:

The function of_irq_parse_one copies the interrupt specifier integers to a struct of_phandle_args here. This arg is then passed to irq_create_of_mapping via a consumer function (e.g. of_irq_get). This function then maps these args to a struct irq_fwspec via of_phandle_args_to_fwspec and passes it's fwspec data to irq_create_fwspec_mapping. These functions are all found in irqdomain.c. At this point the irq will belong to an irq_domain or use the irq_default_domain. As far I can tell - the pca853x driver uses the default domain. This domain is often setup by platform specific code. I found mine by searching for irq_domain_ops on cross reference. A lot of these seem to do simple copying of intspec[1] & IRQ_TYPE_SENSE_MASK to the type variable in irq_create_fwspec_mapping via irq_domain_translate. From here the type is set to the irq's irq_data via irqd_set_trigger_type.

1

Read section 2 in this: Specifying interrupt information for devices ...

2) Interrupt controller nodes

A device is marked as an interrupt controller with the "interrupt-controller" property. This is a empty, boolean property. An additional "#interrupt-cells" property defines the number of cells needed to specify a single interrupt.

It is the responsibility of the interrupt controller's binding to define the length and format of the interrupt specifier. The following two variants are commonly used:

a) one cell


The #interrupt-cells property is set to 1 and the single cell defines the index of the interrupt within the controller.

Example:

   vic: intc@10140000 {
           compatible = "arm,versatile-vic";
           interrupt-controller;
           #interrupt-cells = <1>;
           reg = <0x10140000 0x1000>;
   };

   sic: intc@10003000 {
           compatible = "arm,versatile-sic";
           interrupt-controller;
           #interrupt-cells = <1>;
           reg = <0x10003000 0x1000>;
           interrupt-parent = <&vic>;
           interrupts = <31>; /* Cascaded to vic */
   };

b) two cells


The #interrupt-cells property is set to 2 and the first cell defines the index of the interrupt within the controller, while the second cell is used to specify any of the following flags:

  • bits[3:0] trigger type and level flags

    1 = low-to-high edge triggered
    2 = high-to-low edge triggered
    4 = active high level-sensitive
    8 = active low level-sensitive

Example:

   i2c@7000c000 {
           gpioext: gpio-adnp@41 {
                   compatible = "ad,gpio-adnp";
                   reg = <0x41>;

                   interrupt-parent = <&gpio>;
                   interrupts = <160 1>;

                   gpio-controller;
                   #gpio-cells = <1>;

                   interrupt-controller;
                   #interrupt-cells = <2>;

                   nr-gpios = <64>;
           };

           sx8634@2b {
                   compatible = "smtc,sx8634";
                   reg = <0x2b>;

                   interrupt-parent = <&gpioext>;
                   interrupts = <3 0x8>;

                   #address-cells = <1>;
                   #size-cells = <0>;

                   threshold = <0x40>;
                   sensitivity = <7>;
           };
   };

So for the two cell variant, the first number is an index and the second is a bit mask defining the type of the interrupt input.

This part of the device tree is handled by code in drivers/of/irq.c (e.g. of_irq_parse_one()).

The two lines you refer to in the quoted example declare the device (gpio-exp@21) to be an interrupt controller and any other device that wants to use it must provide two cells per interrupt.

Just above those lines is an example of a device specifying an interrupt in another interrupt controller (not this one, but the device with alias gpio), via the two properties interrupt-parent and interrupts (or you could use the new interrupts-extended which allows different interrupt controllers for each interrupt by specifying the parent as the first cell of the property).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.