Skip to content

Commit 63050a5

Browse files
committed
Merge tag 'pinctrl-v6.1-5' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control fixes from Linus Walleij: "Three driver fixes. The Intel fix looks like the most important. - Fix a potential divide by zero in pinctrl-singe (OMAP and HiSilicon) - Disable IRQs on startup in the Mediatek driver. This is a classic, we should be looking out for this more. - Save and restore pins in 'direct IRQ' mode in the Intel driver, this works around firmware bugs" * tag 'pinctrl-v6.1-5' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: pinctrl: intel: Save and restore pins in "direct IRQ" mode pinctrl: meditatek: Startup with the IRQs disabled pinctrl: single: Fix potential division by zero
2 parents 0e15c3c + 6989ea4 commit 63050a5

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed

drivers/pinctrl/intel/pinctrl-intel.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,9 +436,14 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
436436
writel(value, padcfg0);
437437
}
438438

439+
static int __intel_gpio_get_gpio_mode(u32 value)
440+
{
441+
return (value & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
442+
}
443+
439444
static int intel_gpio_get_gpio_mode(void __iomem *padcfg0)
440445
{
441-
return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
446+
return __intel_gpio_get_gpio_mode(readl(padcfg0));
442447
}
443448

444449
static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
@@ -1674,6 +1679,7 @@ EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data);
16741679
static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin)
16751680
{
16761681
const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
1682+
u32 value;
16771683

16781684
if (!pd || !intel_pad_usable(pctrl, pin))
16791685
return false;
@@ -1688,6 +1694,25 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int
16881694
gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin)))
16891695
return true;
16901696

1697+
/*
1698+
* The firmware on some systems may configure GPIO pins to be
1699+
* an interrupt source in so called "direct IRQ" mode. In such
1700+
* cases the GPIO controller driver has no idea if those pins
1701+
* are being used or not. At the same time, there is a known bug
1702+
* in the firmwares that don't restore the pin settings correctly
1703+
* after suspend, i.e. by an unknown reason the Rx value becomes
1704+
* inverted.
1705+
*
1706+
* Hence, let's save and restore the pins that are configured
1707+
* as GPIOs in the input mode with GPIROUTIOXAPIC bit set.
1708+
*
1709+
* See https://bugzilla.kernel.org/show_bug.cgi?id=214749.
1710+
*/
1711+
value = readl(intel_get_padcfg(pctrl, pin, PADCFG0));
1712+
if ((value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) &&
1713+
(__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO))
1714+
return true;
1715+
16911716
return false;
16921717
}
16931718

drivers/pinctrl/mediatek/mtk-eint.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,12 +303,15 @@ static struct irq_chip mtk_eint_irq_chip = {
303303

304304
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
305305
{
306-
void __iomem *reg = eint->base + eint->regs->dom_en;
306+
void __iomem *dom_en = eint->base + eint->regs->dom_en;
307+
void __iomem *mask_set = eint->base + eint->regs->mask_set;
307308
unsigned int i;
308309

309310
for (i = 0; i < eint->hw->ap_num; i += 32) {
310-
writel(0xffffffff, reg);
311-
reg += 4;
311+
writel(0xffffffff, dom_en);
312+
writel(0xffffffff, mask_set);
313+
dom_en += 4;
314+
mask_set += 4;
312315
}
313316

314317
return 0;

drivers/pinctrl/pinctrl-single.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
727727

728728
mux_bytes = pcs->width / BITS_PER_BYTE;
729729

730-
if (pcs->bits_per_mux) {
730+
if (pcs->bits_per_mux && pcs->fmask) {
731731
pcs->bits_per_pin = fls(pcs->fmask);
732732
nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
733733
} else {

0 commit comments

Comments
 (0)