[PATCH v1 2/5] pinctrl: st: Add Interrupt support.
Linus Walleij
linus.walleij at linaro.org
Wed Jan 15 09:15:34 EST 2014
On Tue, Jan 14, 2014 at 3:52 PM, <srinivas.kandagatla at st.com> wrote:
> ST Pincontroller GPIO bank can have one of the two possible types of
> interrupt-wirings.
Interesting :-)
> +Pin controller node:
> +Required properties:
> - compatible : should be "st,<SOC>-<pio-block>-pinctrl"
> like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
> -- gpio-controller : Indicates this device is a GPIO controller
> -- #gpio-cells : Should be one. The first cell is the pin number.
> +- st,syscfg : Should be a phandle of the syscfg node.
So why do you add this? This is totally unused by your driver.
> - st,retime-pin-mask : Should be mask to specify which pins can be retimed.
> If the property is not present, it is assumed that all the pins in the
> bank are capable of retiming. Retiming is mainly used to improve the
> IO timing margins of external synchronous interfaces.
> -- st,bank-name : Should be a name string for this bank as
> - specified in datasheet.
Why do you have this property? The driver is not using it.
And what is wrong with just using that name for the node?
> -- st,syscfg : Should be a phandle of the syscfg node.
> +- ranges : specifies the ranges for the pin controller memory.
And what are they used for? I've never seen this before.
> +Optional properties:
> +- interrupts : Interrupt number of the irqmux. If the interrupt is shared
> + with other gpio banks via irqmux.
> + a irqline and gpio banks.
> +- reg : irqmux memory resource. If irqmux is present.
> +- reg-names : irqmux resource should be named as "irqmux".
> +
> +GPIO controller node.
> +Required properties:
> +- gpio-controller : Indicates this device is a GPIO controller
> +- #gpio-cells : Should be one. The first cell is the pin number.
> +- st,bank-name : Should be a name string for this bank as specified in
> + datasheet.
Again, why?
> +Optional properties:
> +- interrupts : Interrupt number for this gpio bank. If there is a dedicated
> + interrupt wired up for this gpio bank.
> +
> +- interrupt-controller : Indicates this device is a interrupt controller. GPIO
> + bank can be an interrupt controller iff one of the interrupt type either via
> +irqmux or a dedicated interrupt per bank is specified.
> +
> +- #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
Correct, but reference symbols from:
include/dt-bindings/interrupt-controller/irq.h
in example.
>
> Example:
> pin-controller-sbc {
Please put in an updated example making use of all the
new props.
(...)
> diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
> @@ -271,6 +276,8 @@ struct st_gpio_bank {
> struct pinctrl_gpio_range range;
> void __iomem *base;
> struct st_pio_control pc;
> + struct irq_domain *domain;
> + int gpio_irq;
Why are you putting this IRQ into the state container when it can be
a function local variable in probe()?
> struct st_pinctrl {
> @@ -284,6 +291,8 @@ struct st_pinctrl {
> int ngroups;
> struct regmap *regmap;
> const struct st_pctl_data *data;
> + void __iomem *irqmux_base;
> + int irqmux_irq;
Dito. I think.
> +static int st_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> + struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
> + int virq;
Just name this variable "irq". It is no more virtual than any other
IRQ.
> +
> + if (bank->domain && (offset < chip->ngpio))
> + virq = irq_create_mapping(bank->domain, offset);
No, don't do the create_mapping() call in the .to_irq() function.
Call irq_create_mapping() for *all* valid hwirqs in probe() and use
irq_find_mapping() here.
> +static void st_gpio_irq_disable(struct irq_data *d)
> +{
> + struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
> +
> + writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK);
> +}
> +
> +static void st_gpio_irq_enable(struct irq_data *d)
> +{
> + struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
> +
> + writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK);
> +}
I *strongly* suspect that these two should be replaced with
_mask()/_unmask() rather than using disable/enable.
Because that seems to be what they are doing.
(...)
> +static void __gpio_irq_handler(struct st_gpio_bank *bank)
> +{
> + unsigned long port_in, port_mask, port_comp, port_active;
> + int n;
> +
> + port_in = readl(bank->base + REG_PIO_PIN);
> + port_comp = readl(bank->base + REG_PIO_PCOMP);
> + port_mask = readl(bank->base + REG_PIO_PMASK);
> +
> + port_active = (port_in ^ port_comp) & port_mask;
> +
> + for_each_set_bit(n, &port_active, BITS_PER_LONG) {
> + generic_handle_irq(irq_find_mapping(bank->domain, n));
So what happens if new IRQs appear in the register while you are
inside this loop?
Check this recent patch:
http://marc.info/?l=linux-arm-kernel&m=138979164119464&w=2
Especially this:
+ for (;;) {
+ mask = ioread8(host->base + CLRHILVINT) & 0xff;
+ mask |= (ioread8(host->base + SECOINT) & SECOINT_MASK) << 8;
+ mask |= (ioread8(host->base + PRIMINT) & PRIMINT_MASK) << 8;
+ mask &= host->irq_high_enabled | (host->irq_sys_enabled << 8);
+ if (mask == 0)
+ break;
+ for_each_set_bit(n, &mask, BITS_PER_LONG)
+ generic_handle_irq(irq_find_mapping(host->domain, n));
+ }
> +static struct irq_chip st_gpio_irqchip = {
> + .name = "GPIO",
> + .irq_disable = st_gpio_irq_disable,
> + .irq_mask = st_gpio_irq_disable,
> + .irq_unmask = st_gpio_irq_enable,
Just implement mask/unmask as indicated earlier.
> + .irq_set_type = st_gpio_irq_set_type,
> +};
You need to mark IRQ GPIO lines as used for IRQ.
Add startup() and shutdown() hooks similar to those I add
in this patch:
http://marc.info/?l=linux-gpio&m=138977709114785&w=2
> +static int st_gpio_irq_domain_xlate(struct irq_domain *d,
> + struct device_node *ctrlr, const u32 *intspec, unsigned int intsize,
> + irq_hw_number_t *out_hwirq, unsigned int *out_type)
> +{
> + struct st_gpio_bank *bank = d->host_data;
> + int ret;
> + int pin = bank->gpio_chip.base + intspec[0];
> +
> + if (WARN_ON(intsize < 2))
> + return -EINVAL;
> +
> + *out_hwirq = intspec[0];
> + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
> +
> + ret = gpio_request(pin, ctrlr->full_name);
> + if (ret)
> + return ret;
> +
> + ret = gpio_direction_input(pin);
> + if (ret)
> + return ret;
We recently concluded that you should *NOT* call
gpio_request() and gpio_direction_input() from xlate or similar.
Instead: set up the hardware directly in mask/unmask callbacks
so that the irqchip can trigger IRQs directly without any
interaction with the GPIO subsystem.
By implementing the startup/shutdown hooks as indicated
above you can still indicate to the GPIO subsystem what is
going on and it will enforce that e.g. the line is not set to
output.
> static int st_gpiolib_register_bank(struct st_pinctrl *info,
> @@ -1219,7 +1378,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
> struct pinctrl_gpio_range *range = &bank->range;
> struct device *dev = info->dev;
> int bank_num = of_alias_get_id(np, "gpio");
> - struct resource res;
> + struct resource res, irq_res;
> int err;
>
> if (of_address_to_resource(np, 0, &res))
> @@ -1248,6 +1407,43 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
> }
> dev_info(dev, "%s bank added.\n", range->name);
>
> + /**
> + * GPIO bank can have one of the two possible types of
> + * interrupt-wirings.
> + *
> + * First type is via irqmux, single interrupt is used by multiple
> + * gpio banks. This reduces number of overall interrupts numbers
> + * required. All these banks belong to a single pincontroller.
> + * _________
> + * | |----> [gpio-bank (n) ]
> + * | |----> [gpio-bank (n + 1)]
> + * [irqN]-- | irq-mux |----> [gpio-bank (n + 2)]
> + * | |----> [gpio-bank (... )]
> + * |_________|----> [gpio-bank (n + 7)]
> + *
> + * Second type has a dedicated interrupt per each gpio bank.
> + *
> + * [irqN]----> [gpio-bank (n)]
> + */
> +
> + if (!of_irq_to_resource(np, 0, &irq_res)) {
> + bank->gpio_irq = irq_res.start;
> + irq_set_chained_handler(bank->gpio_irq, st_gpio_irq_handler);
> + irq_set_handler_data(bank->gpio_irq, bank);
> + }
> +
> + if (info->irqmux_irq > 0 || bank->gpio_irq > 0) {
> + /* Setup IRQ domain */
> + bank->domain = irq_domain_add_linear(np,
> + ST_GPIO_PINS_PER_BANK,
> + &st_gpio_irq_ops, bank);
> + if (!bank->domain)
> + dev_err(dev, "Failed to add irq domain for [%s]\n",
> + np->full_name);
> + } else {
> + dev_info(dev, "No IRQ support for [%s] bank\n", np->full_name);
Why is the [bank name] inside [brackets]?
Yours,
Linus Walleij
More information about the linux-arm-kernel
mailing list