Merge tag 'gpio-v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[sfrench/cifs-2.6.git] / drivers / gpio / gpiolib-of.c
index d4e7a09598faedbecb1ccdee24e6138b70e4e7d8..7f1260c78270b57ebd60daee22bbbec939125234 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * OF helpers for the GPIO API
  *
  * Copyright (c) 2007-2008  MontaVista Software, Inc.
  *
  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
  */
 
 #include <linux/device.h>
@@ -58,7 +54,8 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
 }
 
 static void of_gpio_flags_quirks(struct device_node *np,
-                                enum of_gpio_flags *flags)
+                                enum of_gpio_flags *flags,
+                                int index)
 {
        /*
         * Some GPIO fixed regulator quirks.
@@ -92,6 +89,51 @@ static void of_gpio_flags_quirks(struct device_node *np,
                pr_info("%s uses legacy open drain flag - update the DTS if you can\n",
                        of_node_full_name(np));
        }
+
+       /*
+        * Legacy handling of SPI active high chip select. If we have a
+        * property named "cs-gpios" we need to inspect the child node
+        * to determine if the flags should have inverted semantics.
+        */
+       if (IS_ENABLED(CONFIG_SPI_MASTER) &&
+           of_property_read_bool(np, "cs-gpios")) {
+               struct device_node *child;
+               u32 cs;
+               int ret;
+
+               for_each_child_of_node(np, child) {
+                       ret = of_property_read_u32(child, "reg", &cs);
+                       if (!ret)
+                               continue;
+                       if (cs == index) {
+                               /*
+                                * SPI children have active low chip selects
+                                * by default. This can be specified negatively
+                                * by just omitting "spi-cs-high" in the
+                                * device node, or actively by tagging on
+                                * GPIO_ACTIVE_LOW as flag in the device
+                                * tree. If the line is simultaneously
+                                * tagged as active low in the device tree
+                                * and has the "spi-cs-high" set, we get a
+                                * conflict and the "spi-cs-high" flag will
+                                * take precedence.
+                                */
+                               if (of_property_read_bool(np, "spi-cs-high")) {
+                                       if (*flags & OF_GPIO_ACTIVE_LOW) {
+                                               pr_warn("%s GPIO handle specifies active low - ignored\n",
+                                                       of_node_full_name(np));
+                                               *flags &= ~OF_GPIO_ACTIVE_LOW;
+                                       }
+                               } else {
+                                       if (!(*flags & OF_GPIO_ACTIVE_LOW))
+                                               pr_info("%s enforce active low on chipselect handle\n",
+                                                       of_node_full_name(np));
+                                       *flags |= OF_GPIO_ACTIVE_LOW;
+                               }
+                               break;
+                       }
+               }
+       }
 }
 
 /**
@@ -132,7 +174,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
                goto out;
 
        if (flags)
-               of_gpio_flags_quirks(np, flags);
+               of_gpio_flags_quirks(np, flags, index);
 
        pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
                 __func__, propname, np, index,
@@ -349,8 +391,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
        else if (of_property_read_bool(np, "output-high"))
                *dflags |= GPIOD_OUT_HIGH;
        else {
-               pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n",
-                       desc_to_gpio(desc), np->name);
+               pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n",
+                       desc_to_gpio(desc), np);
                return ERR_PTR(-EINVAL);
        }