diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c index b75734ca22dd..85aef54d0aec 100644 --- a/drivers/gpio/gpio-cadence.c +++ b/drivers/gpio/gpio-cadence.c @@ -2,6 +2,7 @@ /* * Copyright 2017-2018 Cadence + * Copyright (C) 2025 Axiado Corporation. * * Authors: * Jan Kotas @@ -31,10 +32,23 @@ #define CDNS_GPIO_IRQ_VALUE 0x28 #define CDNS_GPIO_IRQ_ANY_EDGE 0x2c +struct cdns_gpio_quirks { + bool skip_init; +}; + struct cdns_gpio_chip { struct gpio_generic_chip gen_gc; void __iomem *regs; u32 bypass_orig; + const struct cdns_gpio_quirks *quirks; +}; + +static const struct cdns_gpio_quirks cdns_default_quirks = { + .skip_init = false, +}; + +static const struct cdns_gpio_quirks ax3000_gpio_quirks = { + .skip_init = true, }; static int cdns_gpio_request(struct gpio_chip *chip, unsigned int offset) @@ -141,6 +155,19 @@ static const struct irq_chip cdns_gpio_irqchip = { GPIOCHIP_IRQ_RESOURCE_HELPERS, }; +static const struct of_device_id cdns_of_ids[] = { + { + .compatible = "axiado,ax3000-gpio", + .data = &ax3000_gpio_quirks + }, + { + .compatible = "cdns,gpio-r1p02", + .data = &cdns_default_quirks + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cdns_of_ids); + static int cdns_gpio_probe(struct platform_device *pdev) { struct gpio_generic_chip_config config = { }; @@ -165,6 +192,10 @@ static int cdns_gpio_probe(struct platform_device *pdev) return -EINVAL; } + cgpio->quirks = device_get_match_data(&pdev->dev); + if (!cgpio->quirks) + cgpio->quirks = &cdns_default_quirks; + /* * Set all pins as inputs by default, otherwise: * gpiochip_lock_as_irq: @@ -173,8 +204,15 @@ static int cdns_gpio_probe(struct platform_device *pdev) * so it needs to be changed before gpio_generic_chip_init() is called. */ dir_prev = ioread32(cgpio->regs + CDNS_GPIO_DIRECTION_MODE); - iowrite32(GENMASK(num_gpios - 1, 0), - cgpio->regs + CDNS_GPIO_DIRECTION_MODE); + + /* + * The AX3000 platform performs the required configuration at boot time + * before Linux boots, so this quirk disables pinmux initialization. + */ + if (!cgpio->quirks->skip_init) { + iowrite32(GENMASK(num_gpios - 1, 0), + cgpio->regs + CDNS_GPIO_DIRECTION_MODE); + } config.dev = &pdev->dev; config.sz = 4; @@ -240,9 +278,11 @@ static int cdns_gpio_probe(struct platform_device *pdev) /* * Enable gpio outputs, ignored for input direction */ - iowrite32(GENMASK(num_gpios - 1, 0), - cgpio->regs + CDNS_GPIO_OUTPUT_EN); - iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE); + if (!cgpio->quirks->skip_init) { + iowrite32(GENMASK(num_gpios - 1, 0), + cgpio->regs + CDNS_GPIO_OUTPUT_EN); + iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE); + } platform_set_drvdata(pdev, cgpio); return 0; @@ -260,12 +300,6 @@ static void cdns_gpio_remove(struct platform_device *pdev) iowrite32(cgpio->bypass_orig, cgpio->regs + CDNS_GPIO_BYPASS_MODE); } -static const struct of_device_id cdns_of_ids[] = { - { .compatible = "cdns,gpio-r1p02" }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, cdns_of_ids); - static struct platform_driver cdns_gpio_driver = { .driver = { .name = "cdns-gpio",