Commit d0243693 authored by Tony Lindgren's avatar Tony Lindgren

ARM: OMAP5+: Fix inverted nirq pin interrupts with irq_set_type

Commit 83a86fbb ("irqchip/gic: Loudly complain about the use of
IRQ_TYPE_NONE") started warning about incorrect dts usage for irqs.
ARM GIC only supports active-high interrupts for SPI (Shared Peripheral
Interrupts), and the Palmas PMIC by default is active-low.

Palmas PMIC allows changing the interrupt polarity using register
PALMAS_POLARITY_CTRL_INT_POLARITY, but configuring sys_nirq1 with
a pull-down and setting PALMAS_POLARITY_CTRL_INT_POLARITY made the
Palmas RTC interrupts stop working. This can be easily tested with
kernel tools rtctest.c.

Turns out the SoC inverts the sys_nirq pins for GIC as they do not go
through a peripheral device but go directly to the MPUSS wakeupgen.
I've verified this by muxing the interrupt line temporarily to gpio_wk16
instead of sys_nirq1. with a gpio, the interrupt works fine both
active-low and active-high with the SoC internal pull configured and
palmas polarity configured. But as sys_nirq1, the interrupt only works
when configured ACTIVE_LOW for palmas, and ACTIVE_HIGH for GIC.

Note that there was a similar issue earlier with tegra114 and palmas
interrupt polarity that got fixed by commit df545d1c ("mfd: palmas:
Provide irq flags through DT/platform data"). However, the difference
between omap5 and tegra114 is that tegra inverts the palmas interrupt
twice, once when entering tegra PMC, and again when exiting tegra PMC
to GIC.

Let's fix the issue by adding a custom wakeupgen_irq_set_type() for
wakeupgen and invert any interrupts with wrong polarity. Let's also
warn about any non-sysnirq pins using wrong polarity. Note that we
also need to update the dts for the level as IRQ_TYPE_NONE never
has irq_set_type() called, and let's add some comments and use proper
pin nameing to avoid more confusion later on.

Cc: Belisko Marek <marek.belisko@gmail.com>
Cc: Dmitry Lifshitz <lifshitz@compulab.co.il>
Cc: "Dr. H. Nikolaus Schaller" <hns@goldelico.com>
Cc: Jon Hunter <jonathanh@nvidia.com>
Cc: Keerthy <j-keerthy@ti.com>
Cc: Laxman Dewangan <ldewangan@nvidia.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: Peter Ujfalusi <peter.ujfalusi@ti.com>
Cc: Richard Woodruff <r-woodruff2@ti.com>
Cc: Santosh Shilimkar <ssantosh@kernel.org>
Cc: Tero Kristo <t-kristo@ti.com>
Cc: Thierry Reding <treding@nvidia.com>
Cc: stable@vger.kernel.org # v4.17+
Reported-by: default avatarBelisko Marek <marek.belisko@gmail.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 063c20e1
...@@ -317,7 +317,8 @@ &usbhost_wkup_pins ...@@ -317,7 +317,8 @@ &usbhost_wkup_pins
palmas_sys_nirq_pins: pinmux_palmas_sys_nirq_pins { palmas_sys_nirq_pins: pinmux_palmas_sys_nirq_pins {
pinctrl-single,pins = < pinctrl-single,pins = <
OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq1 */ /* sys_nirq1 is pulled down as the SoC is inverting it for GIC */
OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0)
>; >;
}; };
...@@ -385,7 +386,8 @@ &i2c1 { ...@@ -385,7 +386,8 @@ &i2c1 {
palmas: palmas@48 { palmas: palmas@48 {
compatible = "ti,palmas"; compatible = "ti,palmas";
interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ /* sys_nirq/ext_sys_irq pins get inverted at mpuss wakeupgen */
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_LOW>;
reg = <0x48>; reg = <0x48>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
...@@ -651,7 +653,8 @@ twl6040: twl@4b { ...@@ -651,7 +653,8 @@ twl6040: twl@4b {
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&twl6040_pins>; pinctrl-0 = <&twl6040_pins>;
interrupts = <GIC_SPI 119 IRQ_TYPE_NONE>; /* IRQ_SYS_2N cascaded to gic */ /* sys_nirq/ext_sys_irq pins get inverted at mpuss wakeupgen */
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_LOW>;
/* audpwron gpio defined in the board specific dts */ /* audpwron gpio defined in the board specific dts */
......
...@@ -181,6 +181,13 @@ ads7846_pins: pinmux_ads7846_pins { ...@@ -181,6 +181,13 @@ ads7846_pins: pinmux_ads7846_pins {
OMAP5_IOPAD(0x0042, PIN_INPUT_PULLDOWN | MUX_MODE6) /* llib_wakereqin.gpio1_wk15 */ OMAP5_IOPAD(0x0042, PIN_INPUT_PULLDOWN | MUX_MODE6) /* llib_wakereqin.gpio1_wk15 */
>; >;
}; };
palmas_sys_nirq_pins: pinmux_palmas_sys_nirq_pins {
pinctrl-single,pins = <
/* sys_nirq1 is pulled down as the SoC is inverting it for GIC */
OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0)
>;
};
}; };
&omap5_pmx_core { &omap5_pmx_core {
...@@ -414,8 +421,11 @@ at24@50 { ...@@ -414,8 +421,11 @@ at24@50 {
palmas: palmas@48 { palmas: palmas@48 {
compatible = "ti,palmas"; compatible = "ti,palmas";
interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
reg = <0x48>; reg = <0x48>;
pinctrl-0 = <&palmas_sys_nirq_pins>;
pinctrl-names = "default";
/* sys_nirq/ext_sys_irq pins get inverted at mpuss wakeupgen */
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
ti,system-power-controller; ti,system-power-controller;
......
...@@ -50,6 +50,9 @@ ...@@ -50,6 +50,9 @@
#define OMAP4_NR_BANKS 4 #define OMAP4_NR_BANKS 4
#define OMAP4_NR_IRQS 128 #define OMAP4_NR_IRQS 128
#define SYS_NIRQ1_EXT_SYS_IRQ_1 7
#define SYS_NIRQ2_EXT_SYS_IRQ_2 119
static void __iomem *wakeupgen_base; static void __iomem *wakeupgen_base;
static void __iomem *sar_base; static void __iomem *sar_base;
static DEFINE_RAW_SPINLOCK(wakeupgen_lock); static DEFINE_RAW_SPINLOCK(wakeupgen_lock);
...@@ -153,6 +156,37 @@ static void wakeupgen_unmask(struct irq_data *d) ...@@ -153,6 +156,37 @@ static void wakeupgen_unmask(struct irq_data *d)
irq_chip_unmask_parent(d); irq_chip_unmask_parent(d);
} }
/*
* The sys_nirq pins bypass peripheral modules and are wired directly
* to MPUSS wakeupgen. They get automatically inverted for GIC.
*/
static int wakeupgen_irq_set_type(struct irq_data *d, unsigned int type)
{
bool inverted = false;
switch (type) {
case IRQ_TYPE_LEVEL_LOW:
type &= ~IRQ_TYPE_LEVEL_MASK;
type |= IRQ_TYPE_LEVEL_HIGH;
inverted = true;
break;
case IRQ_TYPE_EDGE_FALLING:
type &= ~IRQ_TYPE_EDGE_BOTH;
type |= IRQ_TYPE_EDGE_RISING;
inverted = true;
break;
default:
break;
}
if (inverted && d->hwirq != SYS_NIRQ1_EXT_SYS_IRQ_1 &&
d->hwirq != SYS_NIRQ2_EXT_SYS_IRQ_2)
pr_warn("wakeupgen: irq%li polarity inverted in dts\n",
d->hwirq);
return irq_chip_set_type_parent(d, type);
}
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static DEFINE_PER_CPU(u32 [MAX_NR_REG_BANKS], irqmasks); static DEFINE_PER_CPU(u32 [MAX_NR_REG_BANKS], irqmasks);
...@@ -446,7 +480,7 @@ static struct irq_chip wakeupgen_chip = { ...@@ -446,7 +480,7 @@ static struct irq_chip wakeupgen_chip = {
.irq_mask = wakeupgen_mask, .irq_mask = wakeupgen_mask,
.irq_unmask = wakeupgen_unmask, .irq_unmask = wakeupgen_unmask,
.irq_retrigger = irq_chip_retrigger_hierarchy, .irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_type = irq_chip_set_type_parent, .irq_set_type = wakeupgen_irq_set_type,
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent, .irq_set_affinity = irq_chip_set_affinity_parent,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment