pinctrl: intel: fix unexpected interrupt

ASUS Chromebook C223 with Celeron N3350 crashes sometimes during
cold booot. Inspection of the kernel log showed that it gets into
an inifite loop logging the following message:

->handle_irq(): 000000009cdb51e8, handle_bad_irq+0x0/0x251
->irq_data.chip(): 000000005ec212a7, 0xffffa043009d8e7
->action(): 00000
IRQ_NOPROBE set
unexpected IRQ trap at vector 7c

The issue happens during cold boot but only if cold boot happens
at most several dozen seconds after Chromebook is powered off. For
longer intervals between power off and power on (cold boot) the issue
does not reproduce. The unexpected interrupt is sourced from INT3452
GPIO pin which is used for SD card detect. Investigation relevealed
that when the interval between power off and power on (cold boot)
is less than several dozen seconds then values of INT3452 GPIO interrupt
enable and interrupt pending registers survive power off and power
on sequence and interrupt for SD card detect pin is enabled and pending
during probe of SD controller which causes the unexpected IRQ message.
"Intel Pentium and Celeron Processor N- and J- Series" volume 3 doc
mentions that GPIO interrupt enable and status registers default
value is 0x0.
The fix clears INT3452 GPIO interrupt enabled and interrupt pending
registers in its probe function.

Fixes: 7981c0015af2 ("pinctrl: intel: Add Intel Sunrisepoint pin controller and GPIO support")
Signed-off-by: Łukasz Bartosik <lb@semihalf.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

authored by Łukasz Bartosik and committed by Andy Shevchenko e986f0e6 77311237

+34 -20
+34 -20
drivers/pinctrl/intel/pinctrl-intel.c
··· 1216 return IRQ_RETVAL(ret); 1217 } 1218 1219 static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl, 1220 const struct intel_community *community) 1221 { ··· 1353 girq->num_parents = 0; 1354 girq->default_type = IRQ_TYPE_NONE; 1355 girq->handler = handle_bad_irq; 1356 1357 ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); 1358 if (ret) { ··· 1728 return 0; 1729 } 1730 EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq); 1731 - 1732 - static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) 1733 - { 1734 - size_t i; 1735 - 1736 - for (i = 0; i < pctrl->ncommunities; i++) { 1737 - const struct intel_community *community; 1738 - void __iomem *base; 1739 - unsigned int gpp; 1740 - 1741 - community = &pctrl->communities[i]; 1742 - base = community->regs; 1743 - 1744 - for (gpp = 0; gpp < community->ngpps; gpp++) { 1745 - /* Mask and clear all interrupts */ 1746 - writel(0, base + community->ie_offset + gpp * 4); 1747 - writel(0xffff, base + community->is_offset + gpp * 4); 1748 - } 1749 - } 1750 - } 1751 1752 static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value) 1753 {
··· 1216 return IRQ_RETVAL(ret); 1217 } 1218 1219 + static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) 1220 + { 1221 + int i; 1222 + 1223 + for (i = 0; i < pctrl->ncommunities; i++) { 1224 + const struct intel_community *community; 1225 + void __iomem *base; 1226 + unsigned int gpp; 1227 + 1228 + community = &pctrl->communities[i]; 1229 + base = community->regs; 1230 + 1231 + for (gpp = 0; gpp < community->ngpps; gpp++) { 1232 + /* Mask and clear all interrupts */ 1233 + writel(0, base + community->ie_offset + gpp * 4); 1234 + writel(0xffff, base + community->is_offset + gpp * 4); 1235 + } 1236 + } 1237 + } 1238 + 1239 + static int intel_gpio_irq_init_hw(struct gpio_chip *gc) 1240 + { 1241 + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); 1242 + 1243 + /* 1244 + * Make sure the interrupt lines are in a proper state before 1245 + * further configuration. 1246 + */ 1247 + intel_gpio_irq_init(pctrl); 1248 + 1249 + return 0; 1250 + } 1251 + 1252 static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl, 1253 const struct intel_community *community) 1254 { ··· 1320 girq->num_parents = 0; 1321 girq->default_type = IRQ_TYPE_NONE; 1322 girq->handler = handle_bad_irq; 1323 + girq->init_hw = intel_gpio_irq_init_hw; 1324 1325 ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); 1326 if (ret) { ··· 1694 return 0; 1695 } 1696 EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq); 1697 1698 static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value) 1699 {