Confusão sobre a configuração # interrupt-cells no expansor PCA9555

1

Estou tentando configurar um arquivo de origem de árvore de dispositivos pela primeira vez na minha plataforma personalizada. Na placa há um expansor gpio NXP PCA9555. Estou tentando configurar o nó para o dispositivo e estou um pouco confuso.

Aqui é onde eu estou com o nó no arquivo dts:

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

Eu cheguei a este ponto usando o armada-388-gp.dts fonte como guia.

Minha confusão está em qual código processa a propriedade #interrupt-cells . A documentação das ligações é não é muito útil para este chip, já que ele não diz nada sobre interpretação de células de interrupção.

Olhando para a função pca953x_irq_setup no código-fonte para o driver pca9555 - não vejo em nenhum lugar que a propriedade #interrupt-cells é manipulada. Isso é tratado no código de manipulação de interrupção do Linux? Estou confuso sobre como devo saber o significado das duas células de interrupção.

pca953x_irq_setup para sua conveniência:

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

Esta é minha primeira vez trabalhando com a árvore de dispositivos, então espero que seja algo óbvio que esteja faltando.

ATUALIZAÇÃO:

Como esclarecimento - estou trabalhando com a versão do kernel 4.12-rc4 no momento.

Agora entendo que estava interpretando erroneamente algumas propriedades da árvore de dispositivos. Anteriormente, eu estava com a impressão de que o motorista tinha que especificar como todas as propriedades eram manipuladas. Vejo agora que o linux realmente manipulará muitas das propriedades genéricas, como gpios ou interrupts (o que faz muito sentido).

Aqui está um pouco mais de uma explicação detalhada de como a tradução de intspec para IRQ_TYPE* acontece:

A função of_irq_parse_one copia os inteiros do especificador de interrupção para um struct of_phandle_args aqui . Este arg é então passado para irq_create_of_mapping através de uma função consumer (por exemplo, of_irq_get ). Essa função mapeia esses argumentos para um struct irq_fwspec via of_phandle_args_to_fwspec e passa seus dados fwspec para irq_create_fwspec_mapping . Essas funções são encontradas em irqdomain.c . Neste ponto, o irq pertencerá a um irq_domain ou usará o irq_default_domain . Até onde posso dizer - o driver pca853x usa o domínio padrão. Esse domínio geralmente é configurado por código específico da plataforma. Eu encontrei o meu procurando irq_domain_ops na referência cruzada . Muitos deles parecem fazer uma cópia simples de intspec[1] & IRQ_TYPE_SENSE_MASK para a variável type em irq_create_fwspec_mapping via irq_domain_translate . A partir daqui, o tipo é definido como irq_data do irq via irqd_set_trigger_type .

    
por zeus_masta_funk 13.06.2017 / 19:01

1 resposta

1

Leia a seção 2 aqui: Especificando informações de interrupção para dispositivos ...

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

     

Exemplo:

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

Portanto, para a variante de duas células, o primeiro número é um índice e o segundo é uma máscara de bits que define o tipo da entrada de interrupção.

Esta parte da árvore de dispositivos é manipulada pelo código em drivers/of/irq.c (por exemplo, of_irq_parse_one() ).

As duas linhas a que você se refere no exemplo citado declaram o dispositivo ( gpio-exp@21 ) como um controlador de interrupção e qualquer outro dispositivo que queira usá-lo deve fornecer duas células por interrupção.

Logo acima dessas linhas há um exemplo de um dispositivo especificando uma interrupção em outro controlador de interrupção (não este, mas o dispositivo com alias gpio ), através das duas propriedades interrupt-parent e interrupts (ou você poderia use o novo interrupts-extended , que permite diferentes controladores de interrupção para cada interrupção, especificando o pai como a primeira célula da propriedade).

    
por 14.06.2017 / 04:15