From 0c3b532ad3fbf82884a2e7e83e37c7dcdd4d1d99 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 5 Apr 2024 19:25:21 +0300 Subject: gpio: wcove: Use -ENOTSUPP consistently The GPIO library expects the drivers to return -ENOTSUPP in some cases and not using analogue POSIX code. Make the driver to follow this. Reviewed-by: Kuppuswamy Sathyanarayanan Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-wcove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index c18b6b47384f..94ca9d03c094 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -104,7 +104,7 @@ static inline int to_reg(int gpio, enum ctrl_register type) unsigned int reg = type == CTRL_IN ? GPIO_IN_CTRL_BASE : GPIO_OUT_CTRL_BASE; if (gpio >= WCOVE_GPIO_NUM) - return -EOPNOTSUPP; + return -ENOTSUPP; return reg + gpio; } -- cgit From ace0ebe5c98d66889f19e0f30e2518d0c58d0e04 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 5 Apr 2024 19:26:22 +0300 Subject: gpio: crystalcove: Use -ENOTSUPP consistently The GPIO library expects the drivers to return -ENOTSUPP in some cases and not using analogue POSIX code. Make the driver to follow this. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-crystalcove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 1ee62cd58582..25db014494a4 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -92,7 +92,7 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) case 0x5e: return GPIOPANELCTL; default: - return -EOPNOTSUPP; + return -ENOTSUPP; } } -- cgit From 7057fc74d6886471b7dcb4faadf56bd71e28296d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Apr 2024 23:21:46 +0300 Subject: gpiolib: acpi: Remove never true check in acpi_get_gpiod_by_index() The acpi_get_gpiod_by_index() never is called with adev being NULL. Remove the redundant check. Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 7f140df40f35..f596edf89451 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -873,9 +873,6 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, struct acpi_gpio_lookup lookup; int ret; - if (!adev) - return ERR_PTR(-ENODEV); - memset(&lookup, 0, sizeof(lookup)); lookup.index = index; -- cgit From d8a26a18d971cd52a9b253aa2cff7dcb20187711 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Apr 2024 23:21:47 +0300 Subject: gpiolib: acpi: Check for errors first in acpi_find_gpio() It's better to parse the code when the usual pattern is being used, i.e. checking for error condition first. There is no functional or code generation change (tested in LLVM). Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index f596edf89451..c2a33beeec50 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -973,10 +973,11 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, else desc = acpi_get_gpiod_from_data(fwnode, propname, idx, &info); - if (!IS_ERR(desc)) - break; if (PTR_ERR(desc) == -EPROBE_DEFER) return ERR_CAST(desc); + + if (!IS_ERR(desc)) + break; } /* Then from plain _CRS GPIOs */ -- cgit From abaed898da91dc6ccaa839c299f9044f301e0b8f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Apr 2024 10:21:02 +0300 Subject: gpio: sch: Switch to memory mapped IO accessors Convert driver to use memory mapped IO accessors. Signed-off-by: Andy Shevchenko Acked-by: William Breathitt Gray Acked-by: Linus Walleij --- drivers/gpio/gpio-sch.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index e48392074e4b..0c765558d03f 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -38,8 +38,8 @@ struct sch_gpio { struct gpio_chip chip; + void __iomem *regs; spinlock_t lock; - unsigned short iobase; unsigned short resume_base; /* GPE handling */ @@ -75,7 +75,7 @@ static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned int gpio, unsigned in offset = sch_gpio_offset(sch, gpio, reg); bit = sch_gpio_bit(sch, gpio); - reg_val = !!(inb(sch->iobase + offset) & BIT(bit)); + reg_val = !!(ioread8(sch->regs + offset) & BIT(bit)); return reg_val; } @@ -89,12 +89,14 @@ static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned int gpio, unsigned i offset = sch_gpio_offset(sch, gpio, reg); bit = sch_gpio_bit(sch, gpio); - reg_val = inb(sch->iobase + offset); + reg_val = ioread8(sch->regs + offset); if (val) - outb(reg_val | BIT(bit), sch->iobase + offset); + reg_val |= BIT(bit); else - outb((reg_val & ~BIT(bit)), sch->iobase + offset); + reg_val &= ~BIT(bit); + + iowrite8(reg_val, sch->regs + offset); } static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num) @@ -267,8 +269,8 @@ static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context) spin_lock_irqsave(&sch->lock, flags); - core_status = inl(sch->iobase + CORE_BANK_OFFSET + GTS); - resume_status = inl(sch->iobase + RESUME_BANK_OFFSET + GTS); + core_status = ioread32(sch->regs + CORE_BANK_OFFSET + GTS); + resume_status = ioread32(sch->regs + RESUME_BANK_OFFSET + GTS); spin_unlock_irqrestore(&sch->lock, flags); @@ -319,9 +321,11 @@ static int sch_gpio_install_gpe_handler(struct sch_gpio *sch) static int sch_gpio_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct gpio_irq_chip *girq; struct sch_gpio *sch; struct resource *res; + void __iomem *regs; int ret; sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL); @@ -332,12 +336,13 @@ static int sch_gpio_probe(struct platform_device *pdev) if (!res) return -EBUSY; - if (!devm_request_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) + regs = devm_ioport_map(dev, res->start, resource_size(res)); + if (!regs) return -EBUSY; + sch->regs = regs; + spin_lock_init(&sch->lock); - sch->iobase = res->start; sch->chip = sch_gpio_chip; sch->chip.label = dev_name(&pdev->dev); sch->chip.parent = &pdev->dev; -- cgit From 2d485d47560eeb6e73f6db10c99f1dab2fa6e08f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2023 16:40:37 +0300 Subject: gpio: sch: Utilise temporary variable for struct device We have a temporary variable to keep a pointer to struct device. Utilise it where it makes sense. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-sch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 0c765558d03f..ff0341b1222f 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -328,7 +328,7 @@ static int sch_gpio_probe(struct platform_device *pdev) void __iomem *regs; int ret; - sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL); + sch = devm_kzalloc(dev, sizeof(*sch), GFP_KERNEL); if (!sch) return -ENOMEM; @@ -344,8 +344,8 @@ static int sch_gpio_probe(struct platform_device *pdev) spin_lock_init(&sch->lock); sch->chip = sch_gpio_chip; - sch->chip.label = dev_name(&pdev->dev); - sch->chip.parent = &pdev->dev; + sch->chip.label = dev_name(dev); + sch->chip.parent = dev; switch (pdev->id) { case PCI_DEVICE_ID_INTEL_SCH_LPC: @@ -399,9 +399,9 @@ static int sch_gpio_probe(struct platform_device *pdev) ret = sch_gpio_install_gpe_handler(sch); if (ret) - dev_warn(&pdev->dev, "Can't setup GPE, no IRQ support\n"); + dev_warn(dev, "Can't setup GPE, no IRQ support\n"); - return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch); + return devm_gpiochip_add_data(dev, &sch->chip, sch); } static struct platform_driver sch_gpio_driver = { -- cgit From 4fa4c499af53c9338a790798ca44534866b7708c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 11 Apr 2024 20:22:29 +0300 Subject: gpiolib: acpi: Extract __acpi_find_gpio() helper We want to reuse it later on in the code. In particular, it helps to clean up the users of acpi_dev_gpio_irq_wake_get_by(). Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c2a33beeec50..d47b22ac3ecb 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -945,14 +945,11 @@ static bool acpi_can_fallback_to_crs(struct acpi_device *adev, return con_id == NULL; } -struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, - const char *con_id, - unsigned int idx, - enum gpiod_flags *dflags, - unsigned long *lookupflags) +static struct gpio_desc * +__acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int idx, + struct acpi_gpio_info *info) { struct acpi_device *adev = to_acpi_device_node(fwnode); - struct acpi_gpio_info info; struct gpio_desc *desc; char propname[32]; int i; @@ -969,10 +966,10 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, if (adev) desc = acpi_get_gpiod_by_index(adev, - propname, idx, &info); + propname, idx, info); else desc = acpi_get_gpiod_from_data(fwnode, - propname, idx, &info); + propname, idx, info); if (PTR_ERR(desc) == -EPROBE_DEFER) return ERR_CAST(desc); @@ -985,11 +982,28 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, if (!adev || !acpi_can_fallback_to_crs(adev, con_id)) return ERR_PTR(-ENOENT); - desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); + desc = acpi_get_gpiod_by_index(adev, NULL, idx, info); if (IS_ERR(desc)) return desc; } + return desc; +} + +struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, + const char *con_id, + unsigned int idx, + enum gpiod_flags *dflags, + unsigned long *lookupflags) +{ + struct acpi_device *adev = to_acpi_device_node(fwnode); + struct acpi_gpio_info info; + struct gpio_desc *desc; + + desc = __acpi_find_gpio(fwnode, con_id, idx, &info); + if (IS_ERR(desc)) + return desc; + if (info.gpioint && (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) { dev_dbg(&adev->dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); -- cgit From 4cd3ef01f60e97422fc9679e4a8d3869188851da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 11 Apr 2024 20:22:30 +0300 Subject: gpiolib: acpi: Simplify error handling in __acpi_find_gpio() Now that we don't perform anything on the GPIO descriptor, we may simplify the error path in newly introduced helper. Do it so. Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d47b22ac3ecb..fb2e14670b7a 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -974,20 +974,14 @@ __acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int return ERR_CAST(desc); if (!IS_ERR(desc)) - break; + return desc; } /* Then from plain _CRS GPIOs */ - if (IS_ERR(desc)) { - if (!adev || !acpi_can_fallback_to_crs(adev, con_id)) - return ERR_PTR(-ENOENT); - - desc = acpi_get_gpiod_by_index(adev, NULL, idx, info); - if (IS_ERR(desc)) - return desc; - } + if (!adev || !acpi_can_fallback_to_crs(adev, con_id)) + return ERR_PTR(-ENOENT); - return desc; + return acpi_get_gpiod_by_index(adev, NULL, idx, info); } struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, -- cgit From 49c02f6e901ca0bcf8c68a0ec8909892eaf43d0d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 11 Apr 2024 20:22:31 +0300 Subject: gpiolib: acpi: Move acpi_can_fallback_to_crs() out of __acpi_find_gpio() New coming user may need to check for _CRS fallback slightly differently. Move the current check out of the helper function to allow that user to use it. Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index fb2e14670b7a..2b3fd43b13fc 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -947,7 +947,7 @@ static bool acpi_can_fallback_to_crs(struct acpi_device *adev, static struct gpio_desc * __acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int idx, - struct acpi_gpio_info *info) + bool can_fallback, struct acpi_gpio_info *info) { struct acpi_device *adev = to_acpi_device_node(fwnode); struct gpio_desc *desc; @@ -978,7 +978,7 @@ __acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int } /* Then from plain _CRS GPIOs */ - if (!adev || !acpi_can_fallback_to_crs(adev, con_id)) + if (!adev || !can_fallback) return ERR_PTR(-ENOENT); return acpi_get_gpiod_by_index(adev, NULL, idx, info); @@ -991,10 +991,11 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, unsigned long *lookupflags) { struct acpi_device *adev = to_acpi_device_node(fwnode); + bool can_fallback = acpi_can_fallback_to_crs(adev, con_id); struct acpi_gpio_info info; struct gpio_desc *desc; - desc = __acpi_find_gpio(fwnode, con_id, idx, &info); + desc = __acpi_find_gpio(fwnode, con_id, idx, can_fallback, &info); if (IS_ERR(desc)) return desc; -- cgit From 57b60ec4b30df188ca31bdd95971a6ef5dfc5094 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 11 Apr 2024 20:22:32 +0300 Subject: gpiolib: acpi: Pass con_id instead of property into acpi_dev_gpio_irq_get_by() Pass the con_id instead of property so that callers won't repeat the GPIO suffixes to try. Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pca953x.c | 2 +- drivers/gpio/gpiolib-acpi.c | 11 +++++------ drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c | 2 +- drivers/pinctrl/pinctrl-cy8c95x0.c | 2 +- include/linux/acpi.h | 8 ++++---- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 00ffa168e405..77a2812f2974 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -144,7 +144,7 @@ static int pca953x_acpi_get_irq(struct device *dev) if (ret) dev_warn(dev, "can't add GPIO ACPI mapping\n"); - ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq-gpios", 0); + ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq", 0); if (ret < 0) return ret; diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 2b3fd43b13fc..909113312a1b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1013,7 +1013,7 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, /** * acpi_dev_gpio_irq_wake_get_by() - Find GpioInt and translate it to Linux IRQ number * @adev: pointer to a ACPI device to get IRQ from - * @name: optional name of GpioInt resource + * @con_id: optional name of GpioInt resource * @index: index of GpioInt resource (starting from %0) * @wake_capable: Set to true if the IRQ is wake capable * @@ -1024,15 +1024,15 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, * The function is idempotent, though each time it runs it will configure GPIO * pin direction according to the flags in GpioInt resource. * - * The function takes optional @name parameter. If the resource has a property - * name, then only those will be taken into account. + * The function takes optional @con_id parameter. If the resource has + * a @con_id in a property, then only those will be taken into account. * * The GPIO is considered wake capable if the GpioInt resource specifies * SharedAndWake or ExclusiveAndWake. * * Return: Linux IRQ number (> %0) on success, negative errno on failure. */ -int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, int index, +int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, int index, bool *wake_capable) { int idx, i; @@ -1043,9 +1043,8 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in struct acpi_gpio_info info; struct gpio_desc *desc; - desc = acpi_get_gpiod_by_index(adev, name, i, &info); - /* Ignore -EPROBE_DEFER, it only matters if idx matches */ + desc = __acpi_find_gpio(acpi_fwnode_handle(adev), con_id, i, true, &info); if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) return PTR_ERR(desc); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 3d09fa54598f..28a0016f1a55 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -428,7 +428,7 @@ static int mlxbf_gige_probe(struct platform_device *pdev) priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); - phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0); + phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy", 0); if (phy_irq < 0) { dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead"); phy_irq = PHY_POLL; diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 67b5d160c027..981c569bd671 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -95,7 +95,7 @@ static int cy8c95x0_acpi_get_irq(struct device *dev) if (ret) dev_warn(dev, "can't add GPIO ACPI mapping\n"); - ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq-gpios", 0); + ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq", 0); if (ret < 0) return ret; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 34829f2c517a..35aff121f418 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1233,7 +1233,7 @@ bool acpi_gpio_get_irq_resource(struct acpi_resource *ares, struct acpi_resource_gpio **agpio); bool acpi_gpio_get_io_resource(struct acpi_resource *ares, struct acpi_resource_gpio **agpio); -int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, int index, +int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, int index, bool *wake_capable); #else static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares, @@ -1246,7 +1246,7 @@ static inline bool acpi_gpio_get_io_resource(struct acpi_resource *ares, { return false; } -static inline int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, +static inline int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, int index, bool *wake_capable) { return -ENXIO; @@ -1259,10 +1259,10 @@ static inline int acpi_dev_gpio_irq_wake_get(struct acpi_device *adev, int index return acpi_dev_gpio_irq_wake_get_by(adev, NULL, index, wake_capable); } -static inline int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, +static inline int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *con_id, int index) { - return acpi_dev_gpio_irq_wake_get_by(adev, name, index, NULL); + return acpi_dev_gpio_irq_wake_get_by(adev, con_id, index, NULL); } static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) -- cgit From 716b532814ffd94792f9033c3ece79145d92d701 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:37:27 +0300 Subject: gpiolib: acpi: Add fwnode name to the GPIO interrupt label It's ambiguous to have a device-related index in the GPIO interrupt label as most of the devices will have it the same or very similar. Extend label with fwnode name for better granularity. It significantly reduces the scope of searching among devices. Ex. (for the PCA9355 and MAX3111e chips connected to the system): === Before === PCA953x: GpioInt() 0 MAX3111e: GpioInt() 0 === After === PCA953x: NIO1 GpioInt(0) MAX3111e: URT0 GpioInt(0) Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 909113312a1b..0b0c8729fc6e 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1035,6 +1035,7 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, int index, bool *wake_capable) { + struct fwnode_handle *fwnode = acpi_fwnode_handle(adev); int idx, i; unsigned int irq_flags; int ret; @@ -1044,7 +1045,7 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, struct gpio_desc *desc; /* Ignore -EPROBE_DEFER, it only matters if idx matches */ - desc = __acpi_find_gpio(acpi_fwnode_handle(adev), con_id, i, true, &info); + desc = __acpi_find_gpio(fwnode, con_id, i, true, &info); if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) return PTR_ERR(desc); @@ -1064,7 +1065,7 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, acpi_gpio_update_gpiod_flags(&dflags, &info); acpi_gpio_update_gpiod_lookup_flags(&lflags, &info); - snprintf(label, sizeof(label), "GpioInt() %d", index); + snprintf(label, sizeof(label), "%pfwP GpioInt(%d)", fwnode, index); ret = gpiod_configure_flags(desc, label, lflags, dflags); if (ret < 0) return ret; -- cgit From 1736df17fea09059f6834da203bcd35fdf35bdf6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:37:28 +0300 Subject: gpiolib: acpi: Set label for IRQ only lines When line locked as IRQ it has no label assigned. Assign the meaningful value to it. Ex. (for the PCA9355 and MAX3111e chips connected to the system): === Before === PCA953x: interrupt MAX3111e: interrupt === After === PCA953x: NIO1 GpioInt(0) MAX3111e: URT0 GpioInt(0) Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 0b0c8729fc6e..553a5f94c00a 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1066,6 +1066,10 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, acpi_gpio_update_gpiod_lookup_flags(&lflags, &info); snprintf(label, sizeof(label), "%pfwP GpioInt(%d)", fwnode, index); + ret = gpiod_set_consumer_name(desc, con_id ?: label); + if (ret) + return ret; + ret = gpiod_configure_flags(desc, label, lflags, dflags); if (ret < 0) return ret; -- cgit From ecc4b1418e2399753af7ef304d01f45e8e942286 Mon Sep 17 00:00:00 2001 From: Aapo Vienamo Date: Tue, 23 Apr 2024 21:13:14 +0300 Subject: gpio: Add Intel Granite Rapids-D vGPIO driver This driver provides a basic GPIO driver for the Intel Granite Rapids-D virtual GPIOs. On SoCs with limited physical pins on the package, the physical pins controlled by this driver would be exposed on an external device such as a BMC or CPLD. The virtual GPIO registers are an interface to firmware, which communicates with the external device that implements the GPIO hardware functionality. Signed-off-by: Aapo Vienamo Reviewed-by: Mika Westerberg Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- MAINTAINERS | 1 + drivers/gpio/Kconfig | 18 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-graniterapids.c | 383 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 403 insertions(+) create mode 100644 drivers/gpio/gpio-graniterapids.c diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..ad1afaf5d1f6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10891,6 +10891,7 @@ L: linux-gpio@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git F: drivers/gpio/gpio-elkhartlake.c +F: drivers/gpio/gpio-graniterapids.c F: drivers/gpio/gpio-ich.c F: drivers/gpio/gpio-merrifield.c F: drivers/gpio/gpio-ml-ioh.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b50d0b470849..f3d7a757da64 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -312,6 +312,24 @@ config GPIO_GENERIC_PLATFORM help Say yes here to support basic platform_device memory-mapped GPIO controllers. +config GPIO_GRANITERAPIDS + tristate "Intel Granite Rapids-D vGPIO support" + depends on X86 || COMPILE_TEST + select GPIOLIB_IRQCHIP + help + Select this to enable virtual GPIO support on platforms with the + following SoCs: + + - Intel Granite Rapids-D + + The driver enables basic GPIO functionality and implements interrupt + support. The virtual GPIO driver controls GPIO lines via a firmware + interface. The physical GPIO pins reside on device that is external + from the main SoC package, such as a BMC or a CPLD. + + To compile this driver as a module, choose M here: the module will + be called gpio-graniterapids. + config GPIO_GRGPIO tristate "Aeroflex Gaisler GRGPIO support" depends on OF_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fdd28c58d890..e2a53013780e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o obj-$(CONFIG_GPIO_FXL6408) += gpio-fxl6408.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o +obj-$(CONFIG_GPIO_GRANITERAPIDS) += gpio-graniterapids.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c new file mode 100644 index 000000000000..c693fe05d50f --- /dev/null +++ b/drivers/gpio/gpio-graniterapids.c @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel Granite Rapids-D vGPIO driver + * + * Copyright (c) 2024, Intel Corporation. + * + * Author: Aapo Vienamo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define GNR_NUM_PINS 128 +#define GNR_PINS_PER_REG 32 +#define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG) + +#define GNR_CFG_BAR 0x00 +#define GNR_CFG_LOCK_OFFSET 0x04 +#define GNR_GPI_STATUS_OFFSET 0x20 +#define GNR_GPI_ENABLE_OFFSET 0x24 + +#define GNR_CFG_DW_RX_MASK GENMASK(25, 22) +#define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2) +#define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1) +#define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0) +#define GNR_CFG_DW_RXDIS BIT(4) +#define GNR_CFG_DW_TXDIS BIT(3) +#define GNR_CFG_DW_RXSTATE BIT(1) +#define GNR_CFG_DW_TXSTATE BIT(0) + +/** + * struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state + * @gc: GPIO controller interface + * @reg_base: base address of the GPIO registers + * @ro_bitmap: bitmap of read-only pins + * @lock: guard the registers + * @pad_backup: backup of the register state for suspend + */ +struct gnr_gpio { + struct gpio_chip gc; + void __iomem *reg_base; + DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS); + raw_spinlock_t lock; + u32 pad_backup[]; +}; + +static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv, + unsigned int gpio) +{ + return priv->reg_base + gpio * sizeof(u32); +} + +static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio, + u32 clear_mask, u32 set_mask) +{ + struct gnr_gpio *priv = gpiochip_get_data(gc); + void __iomem *addr = gnr_gpio_get_padcfg_addr(priv, gpio); + u32 dw; + + if (test_bit(gpio, priv->ro_bitmap)) + return -EACCES; + + guard(raw_spinlock_irqsave)(&priv->lock); + + dw = readl(addr); + dw &= ~clear_mask; + dw |= set_mask; + writel(dw, addr); + + return 0; +} + +static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + const struct gnr_gpio *priv = gpiochip_get_data(gc); + u32 dw; + + dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio)); + + return !!(dw & GNR_CFG_DW_RXSTATE); +} + +static void gnr_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + u32 clear = 0; + u32 set = 0; + + if (value) + set = GNR_CFG_DW_TXSTATE; + else + clear = GNR_CFG_DW_TXSTATE; + + gnr_gpio_configure_line(gc, gpio, clear, set); +} + +static int gnr_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct gnr_gpio *priv = gpiochip_get_data(gc); + u32 dw; + + dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio)); + + if (dw & GNR_CFG_DW_TXDIS) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static int gnr_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) +{ + return gnr_gpio_configure_line(gc, gpio, GNR_CFG_DW_RXDIS, 0); +} + +static int gnr_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, int value) +{ + u32 clear = GNR_CFG_DW_TXDIS; + u32 set = value ? GNR_CFG_DW_TXSTATE : 0; + + return gnr_gpio_configure_line(gc, gpio, clear, set); +} + +static const struct gpio_chip gnr_gpio_chip = { + .owner = THIS_MODULE, + .get = gnr_gpio_get, + .set = gnr_gpio_set, + .get_direction = gnr_gpio_get_direction, + .direction_input = gnr_gpio_direction_input, + .direction_output = gnr_gpio_direction_output, +}; + +static void __iomem *gnr_gpio_get_reg_addr(const struct gnr_gpio *priv, + unsigned int base, + unsigned int gpio) +{ + return priv->reg_base + base + gpio * sizeof(u32); +} + +static void gnr_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gnr_gpio *priv = gpiochip_get_data(gc); + irq_hw_number_t gpio = irqd_to_hwirq(d); + unsigned int reg_idx = gpio / GNR_PINS_PER_REG; + unsigned int bit_idx = gpio % GNR_PINS_PER_REG; + void __iomem *addr = gnr_gpio_get_reg_addr(priv, GNR_GPI_STATUS_OFFSET, reg_idx); + u32 reg; + + guard(raw_spinlock_irqsave)(&priv->lock); + + reg = readl(addr); + reg &= ~BIT(bit_idx); + writel(reg, addr); +} + +static void gnr_gpio_irq_mask_unmask(struct gpio_chip *gc, unsigned long gpio, bool mask) +{ + struct gnr_gpio *priv = gpiochip_get_data(gc); + unsigned int reg_idx = gpio / GNR_PINS_PER_REG; + unsigned int bit_idx = gpio % GNR_PINS_PER_REG; + void __iomem *addr = gnr_gpio_get_reg_addr(priv, GNR_GPI_ENABLE_OFFSET, reg_idx); + u32 reg; + + guard(raw_spinlock_irqsave)(&priv->lock); + + reg = readl(addr); + if (mask) + reg &= ~BIT(bit_idx); + else + reg |= BIT(bit_idx); + writel(reg, addr); +} + +static void gnr_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + gnr_gpio_irq_mask_unmask(gc, hwirq, true); + gpiochip_disable_irq(gc, hwirq); +} + +static void gnr_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + gpiochip_enable_irq(gc, hwirq); + gnr_gpio_irq_mask_unmask(gc, hwirq, false); +} + +static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t pin = irqd_to_hwirq(d); + u32 mask = GNR_CFG_DW_RX_MASK; + u32 set; + + /* Falling edge and level low triggers not supported by the GPIO controller */ + switch (type) { + case IRQ_TYPE_NONE: + set = GNR_CFG_DW_RX_DISABLE; + break; + case IRQ_TYPE_EDGE_RISING: + set = GNR_CFG_DW_RX_EDGE; + irq_set_handler_locked(d, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + set = GNR_CFG_DW_RX_LEVEL; + irq_set_handler_locked(d, handle_level_irq); + break; + default: + return -EINVAL; + } + + return gnr_gpio_configure_line(gc, pin, mask, set); +} + +static const struct irq_chip gnr_gpio_irq_chip = { + .irq_ack = gnr_gpio_irq_ack, + .irq_mask = gnr_gpio_irq_mask, + .irq_unmask = gnr_gpio_irq_unmask, + .irq_set_type = gnr_gpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void gnr_gpio_init_pin_ro_bits(struct device *dev, + const void __iomem *cfg_lock_base, + unsigned long *ro_bitmap) +{ + u32 tmp[GNR_NUM_REGS]; + + memcpy_fromio(tmp, cfg_lock_base, sizeof(tmp)); + bitmap_from_arr32(ro_bitmap, tmp, GNR_NUM_PINS); +} + +static irqreturn_t gnr_gpio_irq(int irq, void *data) +{ + struct gnr_gpio *priv = data; + unsigned int handled = 0; + + for (unsigned int i = 0; i < GNR_NUM_REGS; i++) { + const void __iomem *reg = priv->reg_base + i * sizeof(u32); + unsigned long pending; + unsigned long enabled; + unsigned int bit_idx; + + scoped_guard(raw_spinlock, &priv->lock) { + pending = readl(reg + GNR_GPI_STATUS_OFFSET); + enabled = readl(reg + GNR_GPI_ENABLE_OFFSET); + } + + /* Only enabled interrupts */ + pending &= enabled; + + for_each_set_bit(bit_idx, &pending, GNR_PINS_PER_REG) { + unsigned int hwirq = i * GNR_PINS_PER_REG + bit_idx; + + generic_handle_domain_irq(priv->gc.irq.domain, hwirq); + } + + handled += pending ? 1 : 0; + + } + return IRQ_RETVAL(handled); +} + +static int gnr_gpio_probe(struct platform_device *pdev) +{ + size_t num_backup_pins = IS_ENABLED(CONFIG_PM_SLEEP) ? GNR_NUM_PINS : 0; + struct device *dev = &pdev->dev; + struct gpio_irq_chip *girq; + struct gnr_gpio *priv; + void __iomem *regs; + int irq, ret; + + priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, gnr_gpio_irq, IRQF_SHARED | IRQF_NO_THREAD, + dev_name(dev), priv); + if (ret) + return dev_err_probe(dev, ret, "failed to request interrupt\n"); + + priv->reg_base = regs + readl(regs + GNR_CFG_BAR); + + gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET, + priv->ro_bitmap); + + priv->gc = gnr_gpio_chip; + priv->gc.label = dev_name(dev); + priv->gc.parent = dev; + priv->gc.ngpio = GNR_NUM_PINS; + priv->gc.base = -1; + + girq = &priv->gc.irq; + gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip); + girq->chip->name = dev_name(dev); + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + platform_set_drvdata(pdev, priv); + + return devm_gpiochip_add_data(dev, &priv->gc, priv); +} + +static int gnr_gpio_suspend(struct device *dev) +{ + struct gnr_gpio *priv = dev_get_drvdata(dev); + unsigned int i; + + guard(raw_spinlock_irqsave)(&priv->lock); + + for_each_clear_bit(i, priv->ro_bitmap, priv->gc.ngpio) + priv->pad_backup[i] = readl(gnr_gpio_get_padcfg_addr(priv, i)); + + return 0; +} + +static int gnr_gpio_resume(struct device *dev) +{ + struct gnr_gpio *priv = dev_get_drvdata(dev); + unsigned int i; + + guard(raw_spinlock_irqsave)(&priv->lock); + + for_each_clear_bit(i, priv->ro_bitmap, priv->gc.ngpio) + writel(priv->pad_backup[i], gnr_gpio_get_padcfg_addr(priv, i)); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(gnr_gpio_pm_ops, gnr_gpio_suspend, gnr_gpio_resume); + +static const struct acpi_device_id gnr_gpio_acpi_match[] = { + { "INTC1109" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, gnr_gpio_acpi_match); + +static struct platform_driver gnr_gpio_driver = { + .driver = { + .name = "gpio-graniterapids", + .pm = pm_sleep_ptr(&gnr_gpio_pm_ops), + .acpi_match_table = gnr_gpio_acpi_match, + }, + .probe = gnr_gpio_probe, +}; +module_platform_driver(gnr_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Aapo Vienamo "); +MODULE_DESCRIPTION("Intel Granite Rapids-D vGPIO driver"); -- cgit