Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: acpi: Override GPIO initialization flags

This allows ACPI GPIO code to modify flags based on
ACPI GpioIo() / GpioInt() resources.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Andy Shevchenko and committed by
Linus Walleij
a31f5c3a 2eca25af

+67 -6
+48 -2
drivers/gpio/gpiolib-acpi.c
··· 448 448 } 449 449 } 450 450 451 + int 452 + acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) 453 + { 454 + int ret = 0; 455 + 456 + /* 457 + * Check if the BIOS has IoRestriction with explicitly set direction 458 + * and update @flags accordingly. Otherwise use whatever caller asked 459 + * for. 460 + */ 461 + if (update & GPIOD_FLAGS_BIT_DIR_SET) { 462 + enum gpiod_flags diff = *flags ^ update; 463 + 464 + /* 465 + * Check if caller supplied incompatible GPIO initialization 466 + * flags. 467 + * 468 + * Return %-EINVAL to notify that firmware has different 469 + * settings and we are going to use them. 470 + */ 471 + if (((*flags & GPIOD_FLAGS_BIT_DIR_SET) && (diff & GPIOD_FLAGS_BIT_DIR_OUT)) || 472 + ((*flags & GPIOD_FLAGS_BIT_DIR_OUT) && (diff & GPIOD_FLAGS_BIT_DIR_VAL))) 473 + ret = -EINVAL; 474 + *flags = update; 475 + } 476 + return ret; 477 + } 478 + 451 479 struct acpi_gpio_lookup { 452 480 struct acpi_gpio_info info; 453 481 int index; ··· 513 485 * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH 514 486 */ 515 487 if (lookup->info.gpioint) { 488 + lookup->info.flags = GPIOD_IN; 516 489 lookup->info.polarity = agpio->polarity; 517 490 lookup->info.triggering = agpio->triggering; 491 + } else { 492 + lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio); 518 493 } 519 494 520 495 } ··· 644 613 struct gpio_desc *acpi_find_gpio(struct device *dev, 645 614 const char *con_id, 646 615 unsigned int idx, 647 - enum gpiod_flags flags, 616 + enum gpiod_flags *dflags, 648 617 enum gpio_lookup_flags *lookupflags) 649 618 { 650 619 struct acpi_device *adev = ACPI_COMPANION(dev); 651 620 struct acpi_gpio_info info; 652 621 struct gpio_desc *desc; 653 622 char propname[32]; 623 + int err; 654 624 int i; 655 625 656 626 /* Try first from _DSD */ ··· 682 650 } 683 651 684 652 if (info.gpioint && 685 - (flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH)) { 653 + (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) { 686 654 dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); 687 655 return ERR_PTR(-ENOENT); 688 656 } 689 657 690 658 if (info.polarity == GPIO_ACTIVE_LOW) 691 659 *lookupflags |= GPIO_ACTIVE_LOW; 660 + 661 + err = acpi_gpio_update_gpiod_flags(dflags, info.flags); 662 + if (err) 663 + dev_dbg(dev, "Override GPIO initialization flags\n"); 692 664 693 665 return desc; 694 666 } ··· 747 711 * used to translate from the GPIO offset in the resource to the Linux IRQ 748 712 * number. 749 713 * 714 + * The function is idempotent, though each time it runs it will configure GPIO 715 + * pin direction according to the flags in GpioInt resource. 716 + * 750 717 * Return: Linux IRQ number (>%0) on success, negative errno on failure. 751 718 */ 752 719 int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) 753 720 { 754 721 int idx, i; 755 722 unsigned int irq_flags; 723 + int ret; 756 724 757 725 for (i = 0, idx = 0; idx <= index; i++) { 758 726 struct acpi_gpio_info info; ··· 769 729 return PTR_ERR(desc); 770 730 771 731 if (info.gpioint && idx++ == index) { 732 + char label[32]; 772 733 int irq; 773 734 774 735 if (IS_ERR(desc)) ··· 778 737 irq = gpiod_to_irq(desc); 779 738 if (irq < 0) 780 739 return irq; 740 + 741 + snprintf(label, sizeof(label), "GpioInt() %d", index); 742 + ret = gpiod_configure_flags(desc, label, 0, info.flags); 743 + if (ret < 0) 744 + return ret; 781 745 782 746 irq_flags = acpi_dev_get_irq_type(info.triggering, 783 747 info.polarity);
+6 -2
drivers/gpio/gpiolib.c
··· 3286 3286 desc = of_find_gpio(dev, con_id, idx, &lookupflags); 3287 3287 } else if (ACPI_COMPANION(dev)) { 3288 3288 dev_dbg(dev, "using ACPI for GPIO lookup\n"); 3289 - desc = acpi_find_gpio(dev, con_id, idx, flags, &lookupflags); 3289 + desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags); 3290 3290 } 3291 3291 } 3292 3292 ··· 3367 3367 struct acpi_gpio_info info; 3368 3368 3369 3369 desc = acpi_node_get_gpiod(fwnode, propname, index, &info); 3370 - if (!IS_ERR(desc)) 3370 + if (!IS_ERR(desc)) { 3371 3371 active_low = info.polarity == GPIO_ACTIVE_LOW; 3372 + ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags); 3373 + if (ret) 3374 + pr_debug("Override GPIO initialization flags\n"); 3375 + } 3372 3376 } 3373 3377 3374 3378 if (IS_ERR(desc))
+13 -2
drivers/gpio/gpiolib.h
··· 75 75 76 76 /** 77 77 * struct acpi_gpio_info - ACPI GPIO specific information 78 + * @flags: GPIO initialization flags 78 79 * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo 79 80 * @polarity: interrupt polarity as provided by ACPI 80 81 * @triggering: triggering type as provided by ACPI 81 82 */ 82 83 struct acpi_gpio_info { 84 + enum gpiod_flags flags; 83 85 bool gpioint; 84 86 int polarity; 85 87 int triggering; ··· 123 121 void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); 124 122 void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); 125 123 124 + int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, 125 + enum gpiod_flags update); 126 + 126 127 struct gpio_desc *acpi_find_gpio(struct device *dev, 127 128 const char *con_id, 128 129 unsigned int idx, 129 - enum gpiod_flags flags, 130 + enum gpiod_flags *dflags, 130 131 enum gpio_lookup_flags *lookupflags); 131 132 struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, 132 133 const char *propname, int index, ··· 148 143 static inline void 149 144 acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } 150 145 146 + static inline int 147 + acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) 148 + { 149 + return 0; 150 + } 151 + 151 152 static inline struct gpio_desc * 152 153 acpi_find_gpio(struct device *dev, const char *con_id, 153 - unsigned int idx, enum gpiod_flags flags, 154 + unsigned int idx, enum gpiod_flags *dflags, 154 155 enum gpio_lookup_flags *lookupflags) 155 156 { 156 157 return ERR_PTR(-ENOENT);