gpio_delay_probe() requests the real GPIOs it wraps via
gpio_request_by_name_nodev(), which strdup()s a label into the real
GPIO device's own uc_priv->name[] array. The driver had no .remove
hook, so those requests, and their strdup'd labels, were never
released when the gpio-delay device was torn down.

Add gpio_delay_remove() to free each wrapped real GPIO. Guard each
free with device_active() on the real GPIO's device: generic DM
teardown (e.g. dm_leak_check_end()'s uclass-by-uclass destroy) does
not guarantee a consumer is removed before the provider it wraps, so
the real GPIO device may already be inactive with its uclass_priv
freed by the time this runs.

Fixes: c866f2f197e2 ("gpio: Add GPIO delay driver")
Signed-off-by: Pranav Sanwal <[email protected]>
---

Changes in v2:
- New patch.

 drivers/gpio/gpio-delay.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/gpio/gpio-delay.c b/drivers/gpio/gpio-delay.c
index f6c9c7efb0b..78e79176f3e 100644
--- a/drivers/gpio/gpio-delay.c
+++ b/drivers/gpio/gpio-delay.c
@@ -90,6 +90,20 @@ static int gpio_delay_xlate(struct udevice *dev, struct 
gpio_desc *desc,
        return 0;
 }
 
+static int gpio_delay_remove(struct udevice *dev)
+{
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct gpio_delay_priv *priv = dev_get_priv(dev);
+       int i;
+
+       for (i = 0; i < uc_priv->gpio_count; i++) {
+               if (device_active(priv->descs[i].real_gpio.dev))
+                       dm_gpio_free(dev, &priv->descs[i].real_gpio);
+       }
+
+       return 0;
+}
+
 static const struct dm_gpio_ops gpio_delay_ops = {
        .direction_output = gpio_delay_direction_output,
        .direction_input = gpio_delay_direction_input,
@@ -142,4 +156,5 @@ U_BOOT_DRIVER(gpio_delay) = {
        .ops = &gpio_delay_ops,
        .priv_auto = sizeof(struct gpio_delay_priv),
        .probe = gpio_delay_probe,
+       .remove = gpio_delay_remove,
 };
-- 
2.43.7

Reply via email to