gpio: shared: fix a false-positive sharing detection with reset-gpios

After scanning the devicetree, we remove all entries that have only one
reference, while creating GPIO shared proxies for the remaining, shared
entries. However: for the reset-gpio corner-case, we will have two
references for a "reset-gpios" pin that's not really shared. In this
case one will come from the actual consumer fwnode and the other from
the potential auxiliary reset-gpio device. This causes the GPIO core to
create unnecessary GPIO shared proxy devices for pins that are not
really shared.

Add a function that can detect this situation and remove entries that
have exactly two references but one of them is a reset-gpio.

Fixes: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case")
Link: https://lore.kernel.org/r/20260108-gpio-shared-false-positive-v1-1-5dbf8d1b2f7d@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

Changed files
+32 -2
drivers
+32 -2
drivers/gpio/gpiolib-shared.c
··· 41 41 struct lock_class_key lock_key; 42 42 struct auxiliary_device adev; 43 43 struct gpiod_lookup_table *lookup; 44 + bool is_reset_gpio; 44 45 }; 45 46 46 47 /* Represents a single GPIO pin. */ ··· 113 112 struct gpio_shared_ref *ref; 114 113 115 114 list_for_each_entry(ref, &entry->refs, list) { 116 - if (!ref->fwnode && ref->con_id && strcmp(ref->con_id, "reset") == 0) 115 + if (ref->is_reset_gpio) 116 + /* Already set-up. */ 117 117 return 0; 118 118 } 119 119 120 120 ref = gpio_shared_make_ref(NULL, "reset", flags); 121 121 if (!ref) 122 122 return -ENOMEM; 123 + 124 + ref->is_reset_gpio = true; 123 125 124 126 list_add_tail(&ref->list, &entry->refs); 125 127 ··· 718 714 } 719 715 } 720 716 717 + static bool gpio_shared_entry_is_really_shared(struct gpio_shared_entry *entry) 718 + { 719 + size_t num_nodes = list_count_nodes(&entry->refs); 720 + struct gpio_shared_ref *ref; 721 + 722 + if (num_nodes <= 1) 723 + return false; 724 + 725 + if (num_nodes > 2) 726 + return true; 727 + 728 + /* Exactly two references: */ 729 + list_for_each_entry(ref, &entry->refs, list) { 730 + /* 731 + * Corner-case: the second reference comes from the potential 732 + * reset-gpio instance. However, this pin is not really shared 733 + * as it would have three references in this case. Avoid 734 + * creating unnecessary proxies. 735 + */ 736 + if (ref->is_reset_gpio) 737 + return false; 738 + } 739 + 740 + return true; 741 + } 742 + 721 743 static void gpio_shared_free_exclusive(void) 722 744 { 723 745 struct gpio_shared_entry *entry, *epos; 724 746 725 747 list_for_each_entry_safe(entry, epos, &gpio_shared_list, list) { 726 - if (list_count_nodes(&entry->refs) > 1) 748 + if (gpio_shared_entry_is_really_shared(entry)) 727 749 continue; 728 750 729 751 gpio_shared_drop_ref(list_first_entry(&entry->refs,