mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-19 07:39:54 +02:00
gpio: mlxbf3: Support shutdown() function
[ Upstream commitaad4183232
] During Linux graceful reboot, the GPIO interrupts are not disabled. Since the drivers are not removed during graceful reboot, the logic to call mlxbf3_gpio_irq_disable() is not triggered. Interrupts that remain enabled can cause issues on subsequent boots. For example, the mlxbf-gige driver contains PHY logic to bring up the link. If the gpio-mlxbf3 driver loads first, the mlxbf-gige driver will use a GPIO interrupt to bring up the link. Otherwise, it will use polling. The next time Linux boots and loads the drivers in this order, we encounter the issue: - mlxbf-gige loads first and uses polling while the GPIO10 interrupt is still enabled from the previous boot. So if the interrupt triggers, there is nothing to clear it. - gpio-mlxbf3 loads. - i2c-mlxbf loads. The interrupt doesn't trigger for I2C because it is shared with the GPIO interrupt line which was not cleared. The solution is to add a shutdown function to the GPIO driver to clear and disable all interrupts. Also clear the interrupt after disabling it in mlxbf3_gpio_irq_disable(). Fixes:38a700efc5
("gpio: mlxbf3: Add gpio driver support") Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com> Reviewed-by: David Thompson <davthompson@nvidia.com> Reviewed-by: Andy Shevchenko <andy@kernel.org> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Link: https://lore.kernel.org/r/20240611171509.22151-1-asmaa@nvidia.com Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
fa1d4de726
commit
a8544dec14
|
@ -39,6 +39,8 @@
|
||||||
#define MLXBF_GPIO_CAUSE_OR_EVTEN0 0x14
|
#define MLXBF_GPIO_CAUSE_OR_EVTEN0 0x14
|
||||||
#define MLXBF_GPIO_CAUSE_OR_CLRCAUSE 0x18
|
#define MLXBF_GPIO_CAUSE_OR_CLRCAUSE 0x18
|
||||||
|
|
||||||
|
#define MLXBF_GPIO_CLR_ALL_INTS GENMASK(31, 0)
|
||||||
|
|
||||||
struct mlxbf3_gpio_context {
|
struct mlxbf3_gpio_context {
|
||||||
struct gpio_chip gc;
|
struct gpio_chip gc;
|
||||||
|
|
||||||
|
@ -82,6 +84,8 @@ static void mlxbf3_gpio_irq_disable(struct irq_data *irqd)
|
||||||
val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
||||||
val &= ~BIT(offset);
|
val &= ~BIT(offset);
|
||||||
writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
||||||
|
|
||||||
|
writel(BIT(offset), gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);
|
||||||
raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
|
raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
|
||||||
|
|
||||||
gpiochip_disable_irq(gc, offset);
|
gpiochip_disable_irq(gc, offset);
|
||||||
|
@ -253,6 +257,15 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mlxbf3_gpio_shutdown(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct mlxbf3_gpio_context *gs = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
/* Disable and clear all interrupts */
|
||||||
|
writel(0, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
||||||
|
writel(MLXBF_GPIO_CLR_ALL_INTS, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct acpi_device_id mlxbf3_gpio_acpi_match[] = {
|
static const struct acpi_device_id mlxbf3_gpio_acpi_match[] = {
|
||||||
{ "MLNXBF33", 0 },
|
{ "MLNXBF33", 0 },
|
||||||
{}
|
{}
|
||||||
|
@ -265,6 +278,7 @@ static struct platform_driver mlxbf3_gpio_driver = {
|
||||||
.acpi_match_table = mlxbf3_gpio_acpi_match,
|
.acpi_match_table = mlxbf3_gpio_acpi_match,
|
||||||
},
|
},
|
||||||
.probe = mlxbf3_gpio_probe,
|
.probe = mlxbf3_gpio_probe,
|
||||||
|
.shutdown = mlxbf3_gpio_shutdown,
|
||||||
};
|
};
|
||||||
module_platform_driver(mlxbf3_gpio_driver);
|
module_platform_driver(mlxbf3_gpio_driver);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user