162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OF helpers for the GPIO API
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2007-2008  MontaVista Software, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/errno.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/of_address.h>
1762306a36Sopenharmony_ci#include <linux/of_gpio.h>
1862306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci#include <linux/string.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2362306a36Sopenharmony_ci#include <linux/gpio/machine.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "gpiolib.h"
2662306a36Sopenharmony_ci#include "gpiolib-of.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * This is Linux-specific flags. By default controllers' and Linux' mapping
3062306a36Sopenharmony_ci * match, but GPIO controllers are free to translate their own flags to
3162306a36Sopenharmony_ci * Linux-specific in their .xlate callback. Though, 1:1 mapping is recommended.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_cienum of_gpio_flags {
3462306a36Sopenharmony_ci	OF_GPIO_ACTIVE_LOW = 0x1,
3562306a36Sopenharmony_ci	OF_GPIO_SINGLE_ENDED = 0x2,
3662306a36Sopenharmony_ci	OF_GPIO_OPEN_DRAIN = 0x4,
3762306a36Sopenharmony_ci	OF_GPIO_TRANSITORY = 0x8,
3862306a36Sopenharmony_ci	OF_GPIO_PULL_UP = 0x10,
3962306a36Sopenharmony_ci	OF_GPIO_PULL_DOWN = 0x20,
4062306a36Sopenharmony_ci	OF_GPIO_PULL_DISABLE = 0x40,
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/**
4462306a36Sopenharmony_ci * of_gpio_named_count() - Count GPIOs for a device
4562306a36Sopenharmony_ci * @np:		device node to count GPIOs for
4662306a36Sopenharmony_ci * @propname:	property name containing gpio specifier(s)
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * The function returns the count of GPIOs specified for a node.
4962306a36Sopenharmony_ci * Note that the empty GPIO specifiers count too. Returns either
5062306a36Sopenharmony_ci *   Number of gpios defined in property,
5162306a36Sopenharmony_ci *   -EINVAL for an incorrectly formed gpios property, or
5262306a36Sopenharmony_ci *   -ENOENT for a missing gpios property
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * Example:
5562306a36Sopenharmony_ci * gpios = <0
5662306a36Sopenharmony_ci *          &gpio1 1 2
5762306a36Sopenharmony_ci *          0
5862306a36Sopenharmony_ci *          &gpio2 3 4>;
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * The above example defines four GPIOs, two of which are not specified.
6162306a36Sopenharmony_ci * This function will return '4'
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistatic int of_gpio_named_count(const struct device_node *np,
6462306a36Sopenharmony_ci			       const char *propname)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	return of_count_phandle_with_args(np, propname, "#gpio-cells");
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/**
7062306a36Sopenharmony_ci * of_gpio_spi_cs_get_count() - special GPIO counting for SPI
7162306a36Sopenharmony_ci * @dev:    Consuming device
7262306a36Sopenharmony_ci * @con_id: Function within the GPIO consumer
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * Some elder GPIO controllers need special quirks. Currently we handle
7562306a36Sopenharmony_ci * the Freescale and PPC GPIO controller with bindings that doesn't use the
7662306a36Sopenharmony_ci * established "cs-gpios" for chip selects but instead rely on
7762306a36Sopenharmony_ci * "gpios" for the chip select lines. If we detect this, we redirect
7862306a36Sopenharmony_ci * the counting of "cs-gpios" to count "gpios" transparent to the
7962306a36Sopenharmony_ci * driver.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistatic int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_SPI_MASTER))
8662306a36Sopenharmony_ci		return 0;
8762306a36Sopenharmony_ci	if (!con_id || strcmp(con_id, "cs"))
8862306a36Sopenharmony_ci		return 0;
8962306a36Sopenharmony_ci	if (!of_device_is_compatible(np, "fsl,spi") &&
9062306a36Sopenharmony_ci	    !of_device_is_compatible(np, "aeroflexgaisler,spictrl") &&
9162306a36Sopenharmony_ci	    !of_device_is_compatible(np, "ibm,ppc4xx-spi"))
9262306a36Sopenharmony_ci		return 0;
9362306a36Sopenharmony_ci	return of_gpio_named_count(np, "gpios");
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciint of_gpio_get_count(struct device *dev, const char *con_id)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	int ret;
9962306a36Sopenharmony_ci	char propname[32];
10062306a36Sopenharmony_ci	unsigned int i;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	ret = of_gpio_spi_cs_get_count(dev, con_id);
10362306a36Sopenharmony_ci	if (ret > 0)
10462306a36Sopenharmony_ci		return ret;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
10762306a36Sopenharmony_ci		if (con_id)
10862306a36Sopenharmony_ci			snprintf(propname, sizeof(propname), "%s-%s",
10962306a36Sopenharmony_ci				 con_id, gpio_suffixes[i]);
11062306a36Sopenharmony_ci		else
11162306a36Sopenharmony_ci			snprintf(propname, sizeof(propname), "%s",
11262306a36Sopenharmony_ci				 gpio_suffixes[i]);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		ret = of_gpio_named_count(dev->of_node, propname);
11562306a36Sopenharmony_ci		if (ret > 0)
11662306a36Sopenharmony_ci			break;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci	return ret ? ret : -ENOENT;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct of_phandle_args *gpiospec = data;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return device_match_of_node(&chip->gpiodev->dev, gpiospec->np) &&
12662306a36Sopenharmony_ci				chip->of_xlate &&
12762306a36Sopenharmony_ci				chip->of_xlate(chip, gpiospec, NULL) >= 0;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic struct gpio_chip *of_find_gpiochip_by_xlate(
13162306a36Sopenharmony_ci					struct of_phandle_args *gpiospec)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	return gpiochip_find(gpiospec, of_gpiochip_match_node_and_xlate);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
13762306a36Sopenharmony_ci					struct of_phandle_args *gpiospec,
13862306a36Sopenharmony_ci					enum of_gpio_flags *flags)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	int ret;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (chip->of_gpio_n_cells != gpiospec->args_count)
14362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	ret = chip->of_xlate(chip, gpiospec, flags);
14662306a36Sopenharmony_ci	if (ret < 0)
14762306a36Sopenharmony_ci		return ERR_PTR(ret);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return gpiochip_get_desc(chip, ret);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/*
15362306a36Sopenharmony_ci * Overrides stated polarity of a gpio line and warns when there is a
15462306a36Sopenharmony_ci * discrepancy.
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cistatic void of_gpio_quirk_polarity(const struct device_node *np,
15762306a36Sopenharmony_ci				   bool active_high,
15862306a36Sopenharmony_ci				   enum of_gpio_flags *flags)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	if (active_high) {
16162306a36Sopenharmony_ci		if (*flags & OF_GPIO_ACTIVE_LOW) {
16262306a36Sopenharmony_ci			pr_warn("%s GPIO handle specifies active low - ignored\n",
16362306a36Sopenharmony_ci				of_node_full_name(np));
16462306a36Sopenharmony_ci			*flags &= ~OF_GPIO_ACTIVE_LOW;
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci	} else {
16762306a36Sopenharmony_ci		if (!(*flags & OF_GPIO_ACTIVE_LOW))
16862306a36Sopenharmony_ci			pr_info("%s enforce active low on GPIO handle\n",
16962306a36Sopenharmony_ci				of_node_full_name(np));
17062306a36Sopenharmony_ci		*flags |= OF_GPIO_ACTIVE_LOW;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * This quirk does static polarity overrides in cases where existing
17662306a36Sopenharmony_ci * DTS specified incorrect polarity.
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_cistatic void of_gpio_try_fixup_polarity(const struct device_node *np,
17962306a36Sopenharmony_ci				       const char *propname,
18062306a36Sopenharmony_ci				       enum of_gpio_flags *flags)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	static const struct {
18362306a36Sopenharmony_ci		const char *compatible;
18462306a36Sopenharmony_ci		const char *propname;
18562306a36Sopenharmony_ci		bool active_high;
18662306a36Sopenharmony_ci	} gpios[] = {
18762306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_LCD_HX8357)
18862306a36Sopenharmony_ci		/*
18962306a36Sopenharmony_ci		 * Himax LCD controllers used incorrectly named
19062306a36Sopenharmony_ci		 * "gpios-reset" property and also specified wrong
19162306a36Sopenharmony_ci		 * polarity.
19262306a36Sopenharmony_ci		 */
19362306a36Sopenharmony_ci		{ "himax,hx8357",	"gpios-reset",	false },
19462306a36Sopenharmony_ci		{ "himax,hx8369",	"gpios-reset",	false },
19562306a36Sopenharmony_ci#endif
19662306a36Sopenharmony_ci	};
19762306a36Sopenharmony_ci	unsigned int i;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gpios); i++) {
20062306a36Sopenharmony_ci		if (of_device_is_compatible(np, gpios[i].compatible) &&
20162306a36Sopenharmony_ci		    !strcmp(propname, gpios[i].propname)) {
20262306a36Sopenharmony_ci			of_gpio_quirk_polarity(np, gpios[i].active_high, flags);
20362306a36Sopenharmony_ci			break;
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void of_gpio_set_polarity_by_property(const struct device_node *np,
20962306a36Sopenharmony_ci					     const char *propname,
21062306a36Sopenharmony_ci					     enum of_gpio_flags *flags)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	const struct device_node *np_compat = np;
21362306a36Sopenharmony_ci	const struct device_node *np_propname = np;
21462306a36Sopenharmony_ci	static const struct {
21562306a36Sopenharmony_ci		const char *compatible;
21662306a36Sopenharmony_ci		const char *gpio_propname;
21762306a36Sopenharmony_ci		const char *polarity_propname;
21862306a36Sopenharmony_ci	} gpios[] = {
21962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FEC)
22062306a36Sopenharmony_ci		/* Freescale Fast Ethernet Controller */
22162306a36Sopenharmony_ci		{ "fsl,imx25-fec",   "phy-reset-gpios", "phy-reset-active-high" },
22262306a36Sopenharmony_ci		{ "fsl,imx27-fec",   "phy-reset-gpios", "phy-reset-active-high" },
22362306a36Sopenharmony_ci		{ "fsl,imx28-fec",   "phy-reset-gpios", "phy-reset-active-high" },
22462306a36Sopenharmony_ci		{ "fsl,imx6q-fec",   "phy-reset-gpios", "phy-reset-active-high" },
22562306a36Sopenharmony_ci		{ "fsl,mvf600-fec",  "phy-reset-gpios", "phy-reset-active-high" },
22662306a36Sopenharmony_ci		{ "fsl,imx6sx-fec",  "phy-reset-gpios", "phy-reset-active-high" },
22762306a36Sopenharmony_ci		{ "fsl,imx6ul-fec",  "phy-reset-gpios", "phy-reset-active-high" },
22862306a36Sopenharmony_ci		{ "fsl,imx8mq-fec",  "phy-reset-gpios", "phy-reset-active-high" },
22962306a36Sopenharmony_ci		{ "fsl,imx8qm-fec",  "phy-reset-gpios", "phy-reset-active-high" },
23062306a36Sopenharmony_ci		{ "fsl,s32v234-fec", "phy-reset-gpios", "phy-reset-active-high" },
23162306a36Sopenharmony_ci#endif
23262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_PCI_IMX6)
23362306a36Sopenharmony_ci		{ "fsl,imx6q-pcie",  "reset-gpio", "reset-gpio-active-high" },
23462306a36Sopenharmony_ci		{ "fsl,imx6sx-pcie", "reset-gpio", "reset-gpio-active-high" },
23562306a36Sopenharmony_ci		{ "fsl,imx6qp-pcie", "reset-gpio", "reset-gpio-active-high" },
23662306a36Sopenharmony_ci		{ "fsl,imx7d-pcie",  "reset-gpio", "reset-gpio-active-high" },
23762306a36Sopenharmony_ci		{ "fsl,imx8mq-pcie", "reset-gpio", "reset-gpio-active-high" },
23862306a36Sopenharmony_ci		{ "fsl,imx8mm-pcie", "reset-gpio", "reset-gpio-active-high" },
23962306a36Sopenharmony_ci		{ "fsl,imx8mp-pcie", "reset-gpio", "reset-gpio-active-high" },
24062306a36Sopenharmony_ci#endif
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		/*
24362306a36Sopenharmony_ci		 * The regulator GPIO handles are specified such that the
24462306a36Sopenharmony_ci		 * presence or absence of "enable-active-high" solely controls
24562306a36Sopenharmony_ci		 * the polarity of the GPIO line. Any phandle flags must
24662306a36Sopenharmony_ci		 * be actively ignored.
24762306a36Sopenharmony_ci		 */
24862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_REGULATOR_FIXED_VOLTAGE)
24962306a36Sopenharmony_ci		{ "regulator-fixed",   "gpios",        "enable-active-high" },
25062306a36Sopenharmony_ci		{ "regulator-fixed",   "gpio",         "enable-active-high" },
25162306a36Sopenharmony_ci		{ "reg-fixed-voltage", "gpios",        "enable-active-high" },
25262306a36Sopenharmony_ci		{ "reg-fixed-voltage", "gpio",         "enable-active-high" },
25362306a36Sopenharmony_ci#endif
25462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_REGULATOR_GPIO)
25562306a36Sopenharmony_ci		{ "regulator-gpio",    "enable-gpio",  "enable-active-high" },
25662306a36Sopenharmony_ci		{ "regulator-gpio",    "enable-gpios", "enable-active-high" },
25762306a36Sopenharmony_ci#endif
25862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
25962306a36Sopenharmony_ci		{ "atmel,hsmci",       "cd-gpios",     "cd-inverted" },
26062306a36Sopenharmony_ci#endif
26162306a36Sopenharmony_ci	};
26262306a36Sopenharmony_ci	unsigned int i;
26362306a36Sopenharmony_ci	bool active_high;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
26662306a36Sopenharmony_ci	/*
26762306a36Sopenharmony_ci	 * The Atmel HSMCI has compatible property in the parent node and
26862306a36Sopenharmony_ci	 * gpio property in a child node
26962306a36Sopenharmony_ci	 */
27062306a36Sopenharmony_ci	if (of_device_is_compatible(np->parent, "atmel,hsmci")) {
27162306a36Sopenharmony_ci		np_compat = np->parent;
27262306a36Sopenharmony_ci		np_propname = np;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci#endif
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gpios); i++) {
27762306a36Sopenharmony_ci		if (of_device_is_compatible(np_compat, gpios[i].compatible) &&
27862306a36Sopenharmony_ci		    !strcmp(propname, gpios[i].gpio_propname)) {
27962306a36Sopenharmony_ci			active_high = of_property_read_bool(np_propname,
28062306a36Sopenharmony_ci						gpios[i].polarity_propname);
28162306a36Sopenharmony_ci			of_gpio_quirk_polarity(np, active_high, flags);
28262306a36Sopenharmony_ci			break;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic void of_gpio_flags_quirks(const struct device_node *np,
28862306a36Sopenharmony_ci				 const char *propname,
28962306a36Sopenharmony_ci				 enum of_gpio_flags *flags,
29062306a36Sopenharmony_ci				 int index)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	of_gpio_try_fixup_polarity(np, propname, flags);
29362306a36Sopenharmony_ci	of_gpio_set_polarity_by_property(np, propname, flags);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/*
29662306a36Sopenharmony_ci	 * Legacy open drain handling for fixed voltage regulators.
29762306a36Sopenharmony_ci	 */
29862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_REGULATOR) &&
29962306a36Sopenharmony_ci	    of_device_is_compatible(np, "reg-fixed-voltage") &&
30062306a36Sopenharmony_ci	    of_property_read_bool(np, "gpio-open-drain")) {
30162306a36Sopenharmony_ci		*flags |= (OF_GPIO_SINGLE_ENDED | OF_GPIO_OPEN_DRAIN);
30262306a36Sopenharmony_ci		pr_info("%s uses legacy open drain flag - update the DTS if you can\n",
30362306a36Sopenharmony_ci			of_node_full_name(np));
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/*
30762306a36Sopenharmony_ci	 * Legacy handling of SPI active high chip select. If we have a
30862306a36Sopenharmony_ci	 * property named "cs-gpios" we need to inspect the child node
30962306a36Sopenharmony_ci	 * to determine if the flags should have inverted semantics.
31062306a36Sopenharmony_ci	 */
31162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_SPI_MASTER) && !strcmp(propname, "cs-gpios") &&
31262306a36Sopenharmony_ci	    of_property_read_bool(np, "cs-gpios")) {
31362306a36Sopenharmony_ci		struct device_node *child;
31462306a36Sopenharmony_ci		u32 cs;
31562306a36Sopenharmony_ci		int ret;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		for_each_child_of_node(np, child) {
31862306a36Sopenharmony_ci			ret = of_property_read_u32(child, "reg", &cs);
31962306a36Sopenharmony_ci			if (ret)
32062306a36Sopenharmony_ci				continue;
32162306a36Sopenharmony_ci			if (cs == index) {
32262306a36Sopenharmony_ci				/*
32362306a36Sopenharmony_ci				 * SPI children have active low chip selects
32462306a36Sopenharmony_ci				 * by default. This can be specified negatively
32562306a36Sopenharmony_ci				 * by just omitting "spi-cs-high" in the
32662306a36Sopenharmony_ci				 * device node, or actively by tagging on
32762306a36Sopenharmony_ci				 * GPIO_ACTIVE_LOW as flag in the device
32862306a36Sopenharmony_ci				 * tree. If the line is simultaneously
32962306a36Sopenharmony_ci				 * tagged as active low in the device tree
33062306a36Sopenharmony_ci				 * and has the "spi-cs-high" set, we get a
33162306a36Sopenharmony_ci				 * conflict and the "spi-cs-high" flag will
33262306a36Sopenharmony_ci				 * take precedence.
33362306a36Sopenharmony_ci				 */
33462306a36Sopenharmony_ci				bool active_high = of_property_read_bool(child,
33562306a36Sopenharmony_ci								"spi-cs-high");
33662306a36Sopenharmony_ci				of_gpio_quirk_polarity(child, active_high,
33762306a36Sopenharmony_ci						       flags);
33862306a36Sopenharmony_ci				of_node_put(child);
33962306a36Sopenharmony_ci				break;
34062306a36Sopenharmony_ci			}
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* Legacy handling of stmmac's active-low PHY reset line */
34562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_STMMAC_ETH) &&
34662306a36Sopenharmony_ci	    !strcmp(propname, "snps,reset-gpio") &&
34762306a36Sopenharmony_ci	    of_property_read_bool(np, "snps,reset-active-low"))
34862306a36Sopenharmony_ci		*flags |= OF_GPIO_ACTIVE_LOW;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/**
35262306a36Sopenharmony_ci * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API
35362306a36Sopenharmony_ci * @np:		device node to get GPIO from
35462306a36Sopenharmony_ci * @propname:	property name containing gpio specifier(s)
35562306a36Sopenharmony_ci * @index:	index of the GPIO
35662306a36Sopenharmony_ci * @flags:	a flags pointer to fill in
35762306a36Sopenharmony_ci *
35862306a36Sopenharmony_ci * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
35962306a36Sopenharmony_ci * value on the error condition. If @flags is not NULL the function also fills
36062306a36Sopenharmony_ci * in flags for the GPIO.
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_cistatic struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np,
36362306a36Sopenharmony_ci		     const char *propname, int index, enum of_gpio_flags *flags)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct of_phandle_args gpiospec;
36662306a36Sopenharmony_ci	struct gpio_chip *chip;
36762306a36Sopenharmony_ci	struct gpio_desc *desc;
36862306a36Sopenharmony_ci	int ret;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ret = of_parse_phandle_with_args_map(np, propname, "gpio", index,
37162306a36Sopenharmony_ci					     &gpiospec);
37262306a36Sopenharmony_ci	if (ret) {
37362306a36Sopenharmony_ci		pr_debug("%s: can't parse '%s' property of node '%pOF[%d]'\n",
37462306a36Sopenharmony_ci			__func__, propname, np, index);
37562306a36Sopenharmony_ci		return ERR_PTR(ret);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	chip = of_find_gpiochip_by_xlate(&gpiospec);
37962306a36Sopenharmony_ci	if (!chip) {
38062306a36Sopenharmony_ci		desc = ERR_PTR(-EPROBE_DEFER);
38162306a36Sopenharmony_ci		goto out;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);
38562306a36Sopenharmony_ci	if (IS_ERR(desc))
38662306a36Sopenharmony_ci		goto out;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (flags)
38962306a36Sopenharmony_ci		of_gpio_flags_quirks(np, propname, flags, index);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
39262306a36Sopenharmony_ci		 __func__, propname, np, index,
39362306a36Sopenharmony_ci		 PTR_ERR_OR_ZERO(desc));
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ciout:
39662306a36Sopenharmony_ci	of_node_put(gpiospec.np);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	return desc;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci/**
40262306a36Sopenharmony_ci * of_get_named_gpio() - Get a GPIO number to use with GPIO API
40362306a36Sopenharmony_ci * @np:		device node to get GPIO from
40462306a36Sopenharmony_ci * @propname:	Name of property containing gpio specifier(s)
40562306a36Sopenharmony_ci * @index:	index of the GPIO
40662306a36Sopenharmony_ci *
40762306a36Sopenharmony_ci * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
40862306a36Sopenharmony_ci * value on the error condition.
40962306a36Sopenharmony_ci */
41062306a36Sopenharmony_ciint of_get_named_gpio(const struct device_node *np, const char *propname,
41162306a36Sopenharmony_ci		      int index)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	struct gpio_desc *desc;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	desc = of_get_named_gpiod_flags(np, propname, index, NULL);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (IS_ERR(desc))
41862306a36Sopenharmony_ci		return PTR_ERR(desc);
41962306a36Sopenharmony_ci	else
42062306a36Sopenharmony_ci		return desc_to_gpio(desc);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_get_named_gpio);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci/* Converts gpio_lookup_flags into bitmask of GPIO_* values */
42562306a36Sopenharmony_cistatic unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (flags & OF_GPIO_ACTIVE_LOW)
43062306a36Sopenharmony_ci		lflags |= GPIO_ACTIVE_LOW;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (flags & OF_GPIO_SINGLE_ENDED) {
43362306a36Sopenharmony_ci		if (flags & OF_GPIO_OPEN_DRAIN)
43462306a36Sopenharmony_ci			lflags |= GPIO_OPEN_DRAIN;
43562306a36Sopenharmony_ci		else
43662306a36Sopenharmony_ci			lflags |= GPIO_OPEN_SOURCE;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (flags & OF_GPIO_TRANSITORY)
44062306a36Sopenharmony_ci		lflags |= GPIO_TRANSITORY;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (flags & OF_GPIO_PULL_UP)
44362306a36Sopenharmony_ci		lflags |= GPIO_PULL_UP;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (flags & OF_GPIO_PULL_DOWN)
44662306a36Sopenharmony_ci		lflags |= GPIO_PULL_DOWN;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (flags & OF_GPIO_PULL_DISABLE)
44962306a36Sopenharmony_ci		lflags |= GPIO_PULL_DISABLE;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return lflags;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic struct gpio_desc *of_find_gpio_rename(struct device_node *np,
45562306a36Sopenharmony_ci					     const char *con_id,
45662306a36Sopenharmony_ci					     unsigned int idx,
45762306a36Sopenharmony_ci					     enum of_gpio_flags *of_flags)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	static const struct of_rename_gpio {
46062306a36Sopenharmony_ci		const char *con_id;
46162306a36Sopenharmony_ci		const char *legacy_id;	/* NULL - same as con_id */
46262306a36Sopenharmony_ci		/*
46362306a36Sopenharmony_ci		 * Compatible string can be set to NULL in case where
46462306a36Sopenharmony_ci		 * matching to a particular compatible is not practical,
46562306a36Sopenharmony_ci		 * but it should only be done for gpio names that have
46662306a36Sopenharmony_ci		 * vendor prefix to reduce risk of false positives.
46762306a36Sopenharmony_ci		 * Addition of such entries is strongly discouraged.
46862306a36Sopenharmony_ci		 */
46962306a36Sopenharmony_ci		const char *compatible;
47062306a36Sopenharmony_ci	} gpios[] = {
47162306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_LCD_HX8357)
47262306a36Sopenharmony_ci		/* Himax LCD controllers used "gpios-reset" */
47362306a36Sopenharmony_ci		{ "reset",	"gpios-reset",	"himax,hx8357" },
47462306a36Sopenharmony_ci		{ "reset",	"gpios-reset",	"himax,hx8369" },
47562306a36Sopenharmony_ci#endif
47662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MFD_ARIZONA)
47762306a36Sopenharmony_ci		{ "wlf,reset",	NULL,		NULL },
47862306a36Sopenharmony_ci#endif
47962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_RTC_DRV_MOXART)
48062306a36Sopenharmony_ci		{ "rtc-data",	"gpio-rtc-data",	"moxa,moxart-rtc" },
48162306a36Sopenharmony_ci		{ "rtc-sclk",	"gpio-rtc-sclk",	"moxa,moxart-rtc" },
48262306a36Sopenharmony_ci		{ "rtc-reset",	"gpio-rtc-reset",	"moxa,moxart-rtc" },
48362306a36Sopenharmony_ci#endif
48462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFC_MRVL_I2C)
48562306a36Sopenharmony_ci		{ "reset",	"reset-n-io",	"marvell,nfc-i2c" },
48662306a36Sopenharmony_ci#endif
48762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFC_MRVL_SPI)
48862306a36Sopenharmony_ci		{ "reset",	"reset-n-io",	"marvell,nfc-spi" },
48962306a36Sopenharmony_ci#endif
49062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFC_MRVL_UART)
49162306a36Sopenharmony_ci		{ "reset",	"reset-n-io",	"marvell,nfc-uart" },
49262306a36Sopenharmony_ci		{ "reset",	"reset-n-io",	"mrvl,nfc-uart" },
49362306a36Sopenharmony_ci#endif
49462306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_PCI_LANTIQ)
49562306a36Sopenharmony_ci		/* MIPS Lantiq PCI */
49662306a36Sopenharmony_ci		{ "reset",	"gpios-reset",	"lantiq,pci-xway" },
49762306a36Sopenharmony_ci#endif
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		/*
50062306a36Sopenharmony_ci		 * Some regulator bindings happened before we managed to
50162306a36Sopenharmony_ci		 * establish that GPIO properties should be named
50262306a36Sopenharmony_ci		 * "foo-gpios" so we have this special kludge for them.
50362306a36Sopenharmony_ci		 */
50462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_REGULATOR_ARIZONA_LDO1)
50562306a36Sopenharmony_ci		{ "wlf,ldoena",  NULL,		NULL }, /* Arizona */
50662306a36Sopenharmony_ci#endif
50762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_REGULATOR_WM8994)
50862306a36Sopenharmony_ci		{ "wlf,ldo1ena", NULL,		NULL }, /* WM8994 */
50962306a36Sopenharmony_ci		{ "wlf,ldo2ena", NULL,		NULL }, /* WM8994 */
51062306a36Sopenharmony_ci#endif
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_CS42L56)
51362306a36Sopenharmony_ci		{ "reset",	"cirrus,gpio-nreset",	"cirrus,cs42l56" },
51462306a36Sopenharmony_ci#endif
51562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448)
51662306a36Sopenharmony_ci		{ "i2s1-in-sel-gpio1",	NULL,	"mediatek,mt2701-cs42448-machine" },
51762306a36Sopenharmony_ci		{ "i2s1-in-sel-gpio2",	NULL,	"mediatek,mt2701-cs42448-machine" },
51862306a36Sopenharmony_ci#endif
51962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_TLV320AIC3X)
52062306a36Sopenharmony_ci		{ "reset",	"gpio-reset",	"ti,tlv320aic3x" },
52162306a36Sopenharmony_ci		{ "reset",	"gpio-reset",	"ti,tlv320aic33" },
52262306a36Sopenharmony_ci		{ "reset",	"gpio-reset",	"ti,tlv320aic3007" },
52362306a36Sopenharmony_ci		{ "reset",	"gpio-reset",	"ti,tlv320aic3104" },
52462306a36Sopenharmony_ci		{ "reset",	"gpio-reset",	"ti,tlv320aic3106" },
52562306a36Sopenharmony_ci#endif
52662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SPI_GPIO)
52762306a36Sopenharmony_ci		/*
52862306a36Sopenharmony_ci		 * The SPI GPIO bindings happened before we managed to
52962306a36Sopenharmony_ci		 * establish that GPIO properties should be named
53062306a36Sopenharmony_ci		 * "foo-gpios" so we have this special kludge for them.
53162306a36Sopenharmony_ci		 */
53262306a36Sopenharmony_ci		{ "miso",	"gpio-miso",	"spi-gpio" },
53362306a36Sopenharmony_ci		{ "mosi",	"gpio-mosi",	"spi-gpio" },
53462306a36Sopenharmony_ci		{ "sck",	"gpio-sck",	"spi-gpio" },
53562306a36Sopenharmony_ci#endif
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		/*
53862306a36Sopenharmony_ci		 * The old Freescale bindings use simply "gpios" as name
53962306a36Sopenharmony_ci		 * for the chip select lines rather than "cs-gpios" like
54062306a36Sopenharmony_ci		 * all other SPI hardware. Allow this specifically for
54162306a36Sopenharmony_ci		 * Freescale and PPC devices.
54262306a36Sopenharmony_ci		 */
54362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SPI_FSL_SPI)
54462306a36Sopenharmony_ci		{ "cs",		"gpios",	"fsl,spi" },
54562306a36Sopenharmony_ci		{ "cs",		"gpios",	"aeroflexgaisler,spictrl" },
54662306a36Sopenharmony_ci#endif
54762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SPI_PPC4xx)
54862306a36Sopenharmony_ci		{ "cs",		"gpios",	"ibm,ppc4xx-spi" },
54962306a36Sopenharmony_ci#endif
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_TYPEC_FUSB302)
55262306a36Sopenharmony_ci		/*
55362306a36Sopenharmony_ci		 * Fairchild FUSB302 host is using undocumented "fcs,int_n"
55462306a36Sopenharmony_ci		 * property without the compulsory "-gpios" suffix.
55562306a36Sopenharmony_ci		 */
55662306a36Sopenharmony_ci		{ "fcs,int_n",	NULL,		"fcs,fusb302" },
55762306a36Sopenharmony_ci#endif
55862306a36Sopenharmony_ci	};
55962306a36Sopenharmony_ci	struct gpio_desc *desc;
56062306a36Sopenharmony_ci	const char *legacy_id;
56162306a36Sopenharmony_ci	unsigned int i;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (!con_id)
56462306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gpios); i++) {
56762306a36Sopenharmony_ci		if (strcmp(con_id, gpios[i].con_id))
56862306a36Sopenharmony_ci			continue;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		if (gpios[i].compatible &&
57162306a36Sopenharmony_ci		    !of_device_is_compatible(np, gpios[i].compatible))
57262306a36Sopenharmony_ci			continue;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		legacy_id = gpios[i].legacy_id ?: gpios[i].con_id;
57562306a36Sopenharmony_ci		desc = of_get_named_gpiod_flags(np, legacy_id, idx, of_flags);
57662306a36Sopenharmony_ci		if (!gpiod_not_found(desc)) {
57762306a36Sopenharmony_ci			pr_info("%s uses legacy gpio name '%s' instead of '%s-gpios'\n",
57862306a36Sopenharmony_ci				of_node_full_name(np), legacy_id, con_id);
57962306a36Sopenharmony_ci			return desc;
58062306a36Sopenharmony_ci		}
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return ERR_PTR(-ENOENT);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
58762306a36Sopenharmony_ci					     const char *con_id,
58862306a36Sopenharmony_ci					     unsigned int idx,
58962306a36Sopenharmony_ci					     enum of_gpio_flags *of_flags)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	struct gpio_desc *desc;
59262306a36Sopenharmony_ci	const char *legacy_id;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448))
59562306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (!of_device_is_compatible(np, "mediatek,mt2701-cs42448-machine"))
59862306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (!con_id || strcmp(con_id, "i2s1-in-sel"))
60162306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (idx == 0)
60462306a36Sopenharmony_ci		legacy_id = "i2s1-in-sel-gpio1";
60562306a36Sopenharmony_ci	else if (idx == 1)
60662306a36Sopenharmony_ci		legacy_id = "i2s1-in-sel-gpio2";
60762306a36Sopenharmony_ci	else
60862306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	desc = of_get_named_gpiod_flags(np, legacy_id, 0, of_flags);
61162306a36Sopenharmony_ci	if (!gpiod_not_found(desc))
61262306a36Sopenharmony_ci		pr_info("%s is using legacy gpio name '%s' instead of '%s-gpios'\n",
61362306a36Sopenharmony_ci			of_node_full_name(np), legacy_id, con_id);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	return desc;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_citypedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
61962306a36Sopenharmony_ci						const char *con_id,
62062306a36Sopenharmony_ci						unsigned int idx,
62162306a36Sopenharmony_ci						enum of_gpio_flags *of_flags);
62262306a36Sopenharmony_cistatic const of_find_gpio_quirk of_find_gpio_quirks[] = {
62362306a36Sopenharmony_ci	of_find_gpio_rename,
62462306a36Sopenharmony_ci	of_find_mt2701_gpio,
62562306a36Sopenharmony_ci	NULL
62662306a36Sopenharmony_ci};
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistruct gpio_desc *of_find_gpio(struct device_node *np, const char *con_id,
62962306a36Sopenharmony_ci			       unsigned int idx, unsigned long *flags)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	char prop_name[32]; /* 32 is max size of property name */
63262306a36Sopenharmony_ci	enum of_gpio_flags of_flags;
63362306a36Sopenharmony_ci	const of_find_gpio_quirk *q;
63462306a36Sopenharmony_ci	struct gpio_desc *desc;
63562306a36Sopenharmony_ci	unsigned int i;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	/* Try GPIO property "foo-gpios" and "foo-gpio" */
63862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
63962306a36Sopenharmony_ci		if (con_id)
64062306a36Sopenharmony_ci			snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
64162306a36Sopenharmony_ci				 gpio_suffixes[i]);
64262306a36Sopenharmony_ci		else
64362306a36Sopenharmony_ci			snprintf(prop_name, sizeof(prop_name), "%s",
64462306a36Sopenharmony_ci				 gpio_suffixes[i]);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		desc = of_get_named_gpiod_flags(np, prop_name, idx, &of_flags);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		if (!gpiod_not_found(desc))
64962306a36Sopenharmony_ci			break;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Properly named GPIO was not found, try workarounds */
65362306a36Sopenharmony_ci	for (q = of_find_gpio_quirks; gpiod_not_found(desc) && *q; q++)
65462306a36Sopenharmony_ci		desc = (*q)(np, con_id, idx, &of_flags);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (IS_ERR(desc))
65762306a36Sopenharmony_ci		return desc;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	*flags = of_convert_gpio_flags(of_flags);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	return desc;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/**
66562306a36Sopenharmony_ci * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API
66662306a36Sopenharmony_ci * @np:		device node to get GPIO from
66762306a36Sopenharmony_ci * @chip:	GPIO chip whose hog is parsed
66862306a36Sopenharmony_ci * @idx:	Index of the GPIO to parse
66962306a36Sopenharmony_ci * @name:	GPIO line name
67062306a36Sopenharmony_ci * @lflags:	bitmask of gpio_lookup_flags GPIO_* values - returned from
67162306a36Sopenharmony_ci *		of_find_gpio() or of_parse_own_gpio()
67262306a36Sopenharmony_ci * @dflags:	gpiod_flags - optional GPIO initialization flags
67362306a36Sopenharmony_ci *
67462306a36Sopenharmony_ci * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
67562306a36Sopenharmony_ci * value on the error condition.
67662306a36Sopenharmony_ci */
67762306a36Sopenharmony_cistatic struct gpio_desc *of_parse_own_gpio(struct device_node *np,
67862306a36Sopenharmony_ci					   struct gpio_chip *chip,
67962306a36Sopenharmony_ci					   unsigned int idx, const char **name,
68062306a36Sopenharmony_ci					   unsigned long *lflags,
68162306a36Sopenharmony_ci					   enum gpiod_flags *dflags)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct device_node *chip_np;
68462306a36Sopenharmony_ci	enum of_gpio_flags xlate_flags;
68562306a36Sopenharmony_ci	struct of_phandle_args gpiospec;
68662306a36Sopenharmony_ci	struct gpio_desc *desc;
68762306a36Sopenharmony_ci	unsigned int i;
68862306a36Sopenharmony_ci	u32 tmp;
68962306a36Sopenharmony_ci	int ret;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	chip_np = dev_of_node(&chip->gpiodev->dev);
69262306a36Sopenharmony_ci	if (!chip_np)
69362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	xlate_flags = 0;
69662306a36Sopenharmony_ci	*lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
69762306a36Sopenharmony_ci	*dflags = GPIOD_ASIS;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
70062306a36Sopenharmony_ci	if (ret)
70162306a36Sopenharmony_ci		return ERR_PTR(ret);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	gpiospec.np = chip_np;
70462306a36Sopenharmony_ci	gpiospec.args_count = tmp;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	for (i = 0; i < tmp; i++) {
70762306a36Sopenharmony_ci		ret = of_property_read_u32_index(np, "gpios", idx * tmp + i,
70862306a36Sopenharmony_ci						 &gpiospec.args[i]);
70962306a36Sopenharmony_ci		if (ret)
71062306a36Sopenharmony_ci			return ERR_PTR(ret);
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, &xlate_flags);
71462306a36Sopenharmony_ci	if (IS_ERR(desc))
71562306a36Sopenharmony_ci		return desc;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	*lflags = of_convert_gpio_flags(xlate_flags);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (of_property_read_bool(np, "input"))
72062306a36Sopenharmony_ci		*dflags |= GPIOD_IN;
72162306a36Sopenharmony_ci	else if (of_property_read_bool(np, "output-low"))
72262306a36Sopenharmony_ci		*dflags |= GPIOD_OUT_LOW;
72362306a36Sopenharmony_ci	else if (of_property_read_bool(np, "output-high"))
72462306a36Sopenharmony_ci		*dflags |= GPIOD_OUT_HIGH;
72562306a36Sopenharmony_ci	else {
72662306a36Sopenharmony_ci		pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n",
72762306a36Sopenharmony_ci			desc_to_gpio(desc), np);
72862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (name && of_property_read_string(np, "line-name", name))
73262306a36Sopenharmony_ci		*name = np->name;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	return desc;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci/**
73862306a36Sopenharmony_ci * of_gpiochip_add_hog - Add all hogs in a hog device node
73962306a36Sopenharmony_ci * @chip:	gpio chip to act on
74062306a36Sopenharmony_ci * @hog:	device node describing the hogs
74162306a36Sopenharmony_ci *
74262306a36Sopenharmony_ci * Returns error if it fails otherwise 0 on success.
74362306a36Sopenharmony_ci */
74462306a36Sopenharmony_cistatic int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	enum gpiod_flags dflags;
74762306a36Sopenharmony_ci	struct gpio_desc *desc;
74862306a36Sopenharmony_ci	unsigned long lflags;
74962306a36Sopenharmony_ci	const char *name;
75062306a36Sopenharmony_ci	unsigned int i;
75162306a36Sopenharmony_ci	int ret;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	for (i = 0;; i++) {
75462306a36Sopenharmony_ci		desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags);
75562306a36Sopenharmony_ci		if (IS_ERR(desc))
75662306a36Sopenharmony_ci			break;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		ret = gpiod_hog(desc, name, lflags, dflags);
75962306a36Sopenharmony_ci		if (ret < 0)
76062306a36Sopenharmony_ci			return ret;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci#ifdef CONFIG_OF_DYNAMIC
76362306a36Sopenharmony_ci		desc->hog = hog;
76462306a36Sopenharmony_ci#endif
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	return 0;
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci/**
77162306a36Sopenharmony_ci * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
77262306a36Sopenharmony_ci * @chip:	gpio chip to act on
77362306a36Sopenharmony_ci *
77462306a36Sopenharmony_ci * This is only used by of_gpiochip_add to request/set GPIO initial
77562306a36Sopenharmony_ci * configuration.
77662306a36Sopenharmony_ci * It returns error if it fails otherwise 0 on success.
77762306a36Sopenharmony_ci */
77862306a36Sopenharmony_cistatic int of_gpiochip_scan_gpios(struct gpio_chip *chip)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	struct device_node *np;
78162306a36Sopenharmony_ci	int ret;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	for_each_available_child_of_node(dev_of_node(&chip->gpiodev->dev), np) {
78462306a36Sopenharmony_ci		if (!of_property_read_bool(np, "gpio-hog"))
78562306a36Sopenharmony_ci			continue;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		ret = of_gpiochip_add_hog(chip, np);
78862306a36Sopenharmony_ci		if (ret < 0) {
78962306a36Sopenharmony_ci			of_node_put(np);
79062306a36Sopenharmony_ci			return ret;
79162306a36Sopenharmony_ci		}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		of_node_set_flag(np, OF_POPULATED);
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	return 0;
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci#ifdef CONFIG_OF_DYNAMIC
80062306a36Sopenharmony_ci/**
80162306a36Sopenharmony_ci * of_gpiochip_remove_hog - Remove all hogs in a hog device node
80262306a36Sopenharmony_ci * @chip:	gpio chip to act on
80362306a36Sopenharmony_ci * @hog:	device node describing the hogs
80462306a36Sopenharmony_ci */
80562306a36Sopenharmony_cistatic void of_gpiochip_remove_hog(struct gpio_chip *chip,
80662306a36Sopenharmony_ci				   struct device_node *hog)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct gpio_desc *desc;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	for_each_gpio_desc_with_flag(chip, desc, FLAG_IS_HOGGED)
81162306a36Sopenharmony_ci		if (desc->hog == hog)
81262306a36Sopenharmony_ci			gpiochip_free_own_desc(desc);
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	return device_match_of_node(&chip->gpiodev->dev, data);
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	return gpiochip_find(np, of_gpiochip_match_node);
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic int of_gpio_notify(struct notifier_block *nb, unsigned long action,
82662306a36Sopenharmony_ci			  void *arg)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct of_reconfig_data *rd = arg;
82962306a36Sopenharmony_ci	struct gpio_chip *chip;
83062306a36Sopenharmony_ci	int ret;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	/*
83362306a36Sopenharmony_ci	 * This only supports adding and removing complete gpio-hog nodes.
83462306a36Sopenharmony_ci	 * Modifying an existing gpio-hog node is not supported (except for
83562306a36Sopenharmony_ci	 * changing its "status" property, which is treated the same as
83662306a36Sopenharmony_ci	 * addition/removal).
83762306a36Sopenharmony_ci	 */
83862306a36Sopenharmony_ci	switch (of_reconfig_get_state_change(action, arg)) {
83962306a36Sopenharmony_ci	case OF_RECONFIG_CHANGE_ADD:
84062306a36Sopenharmony_ci		if (!of_property_read_bool(rd->dn, "gpio-hog"))
84162306a36Sopenharmony_ci			return NOTIFY_OK;	/* not for us */
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
84462306a36Sopenharmony_ci			return NOTIFY_OK;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		chip = of_find_gpiochip_by_node(rd->dn->parent);
84762306a36Sopenharmony_ci		if (chip == NULL)
84862306a36Sopenharmony_ci			return NOTIFY_OK;	/* not for us */
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		ret = of_gpiochip_add_hog(chip, rd->dn);
85162306a36Sopenharmony_ci		if (ret < 0) {
85262306a36Sopenharmony_ci			pr_err("%s: failed to add hogs for %pOF\n", __func__,
85362306a36Sopenharmony_ci			       rd->dn);
85462306a36Sopenharmony_ci			of_node_clear_flag(rd->dn, OF_POPULATED);
85562306a36Sopenharmony_ci			return notifier_from_errno(ret);
85662306a36Sopenharmony_ci		}
85762306a36Sopenharmony_ci		break;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	case OF_RECONFIG_CHANGE_REMOVE:
86062306a36Sopenharmony_ci		if (!of_node_check_flag(rd->dn, OF_POPULATED))
86162306a36Sopenharmony_ci			return NOTIFY_OK;	/* already depopulated */
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		chip = of_find_gpiochip_by_node(rd->dn->parent);
86462306a36Sopenharmony_ci		if (chip == NULL)
86562306a36Sopenharmony_ci			return NOTIFY_OK;	/* not for us */
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		of_gpiochip_remove_hog(chip, rd->dn);
86862306a36Sopenharmony_ci		of_node_clear_flag(rd->dn, OF_POPULATED);
86962306a36Sopenharmony_ci		break;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	return NOTIFY_OK;
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistruct notifier_block gpio_of_notifier = {
87662306a36Sopenharmony_ci	.notifier_call = of_gpio_notify,
87762306a36Sopenharmony_ci};
87862306a36Sopenharmony_ci#endif /* CONFIG_OF_DYNAMIC */
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci/**
88162306a36Sopenharmony_ci * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
88262306a36Sopenharmony_ci * @gc:		pointer to the gpio_chip structure
88362306a36Sopenharmony_ci * @gpiospec:	GPIO specifier as found in the device tree
88462306a36Sopenharmony_ci * @flags:	a flags pointer to fill in
88562306a36Sopenharmony_ci *
88662306a36Sopenharmony_ci * This is simple translation function, suitable for the most 1:1 mapped
88762306a36Sopenharmony_ci * GPIO chips. This function performs only one sanity check: whether GPIO
88862306a36Sopenharmony_ci * is less than ngpios (that is specified in the gpio_chip).
88962306a36Sopenharmony_ci */
89062306a36Sopenharmony_cistatic int of_gpio_simple_xlate(struct gpio_chip *gc,
89162306a36Sopenharmony_ci				const struct of_phandle_args *gpiospec,
89262306a36Sopenharmony_ci				u32 *flags)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	/*
89562306a36Sopenharmony_ci	 * We're discouraging gpio_cells < 2, since that way you'll have to
89662306a36Sopenharmony_ci	 * write your own xlate function (that will have to retrieve the GPIO
89762306a36Sopenharmony_ci	 * number and the flags from a single gpio cell -- this is possible,
89862306a36Sopenharmony_ci	 * but not recommended).
89962306a36Sopenharmony_ci	 */
90062306a36Sopenharmony_ci	if (gc->of_gpio_n_cells < 2) {
90162306a36Sopenharmony_ci		WARN_ON(1);
90262306a36Sopenharmony_ci		return -EINVAL;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
90662306a36Sopenharmony_ci		return -EINVAL;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if (gpiospec->args[0] >= gc->ngpio)
90962306a36Sopenharmony_ci		return -EINVAL;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	if (flags)
91262306a36Sopenharmony_ci		*flags = gpiospec->args[1];
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	return gpiospec->args[0];
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP)
91862306a36Sopenharmony_ci#include <linux/gpio/legacy-of-mm-gpiochip.h>
91962306a36Sopenharmony_ci/**
92062306a36Sopenharmony_ci * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
92162306a36Sopenharmony_ci * @np:		device node of the GPIO chip
92262306a36Sopenharmony_ci * @mm_gc:	pointer to the of_mm_gpio_chip allocated structure
92362306a36Sopenharmony_ci * @data:	driver data to store in the struct gpio_chip
92462306a36Sopenharmony_ci *
92562306a36Sopenharmony_ci * To use this function you should allocate and fill mm_gc with:
92662306a36Sopenharmony_ci *
92762306a36Sopenharmony_ci * 1) In the gpio_chip structure:
92862306a36Sopenharmony_ci *    - all the callbacks
92962306a36Sopenharmony_ci *    - of_gpio_n_cells
93062306a36Sopenharmony_ci *    - of_xlate callback (optional)
93162306a36Sopenharmony_ci *
93262306a36Sopenharmony_ci * 3) In the of_mm_gpio_chip structure:
93362306a36Sopenharmony_ci *    - save_regs callback (optional)
93462306a36Sopenharmony_ci *
93562306a36Sopenharmony_ci * If succeeded, this function will map bank's memory and will
93662306a36Sopenharmony_ci * do all necessary work for you. Then you'll able to use .regs
93762306a36Sopenharmony_ci * to manage GPIOs from the callbacks.
93862306a36Sopenharmony_ci */
93962306a36Sopenharmony_ciint of_mm_gpiochip_add_data(struct device_node *np,
94062306a36Sopenharmony_ci			    struct of_mm_gpio_chip *mm_gc,
94162306a36Sopenharmony_ci			    void *data)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	int ret = -ENOMEM;
94462306a36Sopenharmony_ci	struct gpio_chip *gc = &mm_gc->gc;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	gc->label = kasprintf(GFP_KERNEL, "%pOF", np);
94762306a36Sopenharmony_ci	if (!gc->label)
94862306a36Sopenharmony_ci		goto err0;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	mm_gc->regs = of_iomap(np, 0);
95162306a36Sopenharmony_ci	if (!mm_gc->regs)
95262306a36Sopenharmony_ci		goto err1;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	gc->base = -1;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (mm_gc->save_regs)
95762306a36Sopenharmony_ci		mm_gc->save_regs(mm_gc);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	fwnode_handle_put(mm_gc->gc.fwnode);
96062306a36Sopenharmony_ci	mm_gc->gc.fwnode = fwnode_handle_get(of_fwnode_handle(np));
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	ret = gpiochip_add_data(gc, data);
96362306a36Sopenharmony_ci	if (ret)
96462306a36Sopenharmony_ci		goto err2;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	return 0;
96762306a36Sopenharmony_cierr2:
96862306a36Sopenharmony_ci	of_node_put(np);
96962306a36Sopenharmony_ci	iounmap(mm_gc->regs);
97062306a36Sopenharmony_cierr1:
97162306a36Sopenharmony_ci	kfree(gc->label);
97262306a36Sopenharmony_cierr0:
97362306a36Sopenharmony_ci	pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret);
97462306a36Sopenharmony_ci	return ret;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci/**
97962306a36Sopenharmony_ci * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
98062306a36Sopenharmony_ci * @mm_gc:	pointer to the of_mm_gpio_chip allocated structure
98162306a36Sopenharmony_ci */
98262306a36Sopenharmony_civoid of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct gpio_chip *gc = &mm_gc->gc;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	gpiochip_remove(gc);
98762306a36Sopenharmony_ci	iounmap(mm_gc->regs);
98862306a36Sopenharmony_ci	kfree(gc->label);
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
99162306a36Sopenharmony_ci#endif
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci#ifdef CONFIG_PINCTRL
99462306a36Sopenharmony_cistatic int of_gpiochip_add_pin_range(struct gpio_chip *chip)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	struct of_phandle_args pinspec;
99762306a36Sopenharmony_ci	struct pinctrl_dev *pctldev;
99862306a36Sopenharmony_ci	struct device_node *np;
99962306a36Sopenharmony_ci	int index = 0, ret;
100062306a36Sopenharmony_ci	const char *name;
100162306a36Sopenharmony_ci	static const char group_names_propname[] = "gpio-ranges-group-names";
100262306a36Sopenharmony_ci	struct property *group_names;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	np = dev_of_node(&chip->gpiodev->dev);
100562306a36Sopenharmony_ci	if (!np)
100662306a36Sopenharmony_ci		return 0;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	group_names = of_find_property(np, group_names_propname, NULL);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	for (;; index++) {
101162306a36Sopenharmony_ci		ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
101262306a36Sopenharmony_ci				index, &pinspec);
101362306a36Sopenharmony_ci		if (ret)
101462306a36Sopenharmony_ci			break;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci		pctldev = of_pinctrl_get(pinspec.np);
101762306a36Sopenharmony_ci		of_node_put(pinspec.np);
101862306a36Sopenharmony_ci		if (!pctldev)
101962306a36Sopenharmony_ci			return -EPROBE_DEFER;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		if (pinspec.args[2]) {
102262306a36Sopenharmony_ci			if (group_names) {
102362306a36Sopenharmony_ci				of_property_read_string_index(np,
102462306a36Sopenharmony_ci						group_names_propname,
102562306a36Sopenharmony_ci						index, &name);
102662306a36Sopenharmony_ci				if (strlen(name)) {
102762306a36Sopenharmony_ci					pr_err("%pOF: Group name of numeric GPIO ranges must be the empty string.\n",
102862306a36Sopenharmony_ci						np);
102962306a36Sopenharmony_ci					break;
103062306a36Sopenharmony_ci				}
103162306a36Sopenharmony_ci			}
103262306a36Sopenharmony_ci			/* npins != 0: linear range */
103362306a36Sopenharmony_ci			ret = gpiochip_add_pin_range(chip,
103462306a36Sopenharmony_ci					pinctrl_dev_get_devname(pctldev),
103562306a36Sopenharmony_ci					pinspec.args[0],
103662306a36Sopenharmony_ci					pinspec.args[1],
103762306a36Sopenharmony_ci					pinspec.args[2]);
103862306a36Sopenharmony_ci			if (ret)
103962306a36Sopenharmony_ci				return ret;
104062306a36Sopenharmony_ci		} else {
104162306a36Sopenharmony_ci			/* npins == 0: special range */
104262306a36Sopenharmony_ci			if (pinspec.args[1]) {
104362306a36Sopenharmony_ci				pr_err("%pOF: Illegal gpio-range format.\n",
104462306a36Sopenharmony_ci					np);
104562306a36Sopenharmony_ci				break;
104662306a36Sopenharmony_ci			}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci			if (!group_names) {
104962306a36Sopenharmony_ci				pr_err("%pOF: GPIO group range requested but no %s property.\n",
105062306a36Sopenharmony_ci					np, group_names_propname);
105162306a36Sopenharmony_ci				break;
105262306a36Sopenharmony_ci			}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci			ret = of_property_read_string_index(np,
105562306a36Sopenharmony_ci						group_names_propname,
105662306a36Sopenharmony_ci						index, &name);
105762306a36Sopenharmony_ci			if (ret)
105862306a36Sopenharmony_ci				break;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci			if (!strlen(name)) {
106162306a36Sopenharmony_ci				pr_err("%pOF: Group name of GPIO group range cannot be the empty string.\n",
106262306a36Sopenharmony_ci				np);
106362306a36Sopenharmony_ci				break;
106462306a36Sopenharmony_ci			}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci			ret = gpiochip_add_pingroup_range(chip, pctldev,
106762306a36Sopenharmony_ci						pinspec.args[0], name);
106862306a36Sopenharmony_ci			if (ret)
106962306a36Sopenharmony_ci				return ret;
107062306a36Sopenharmony_ci		}
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	return 0;
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci#else
107762306a36Sopenharmony_cistatic int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
107862306a36Sopenharmony_ci#endif
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ciint of_gpiochip_add(struct gpio_chip *chip)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	struct device_node *np;
108362306a36Sopenharmony_ci	int ret;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	np = dev_of_node(&chip->gpiodev->dev);
108662306a36Sopenharmony_ci	if (!np)
108762306a36Sopenharmony_ci		return 0;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (!chip->of_xlate) {
109062306a36Sopenharmony_ci		chip->of_gpio_n_cells = 2;
109162306a36Sopenharmony_ci		chip->of_xlate = of_gpio_simple_xlate;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
109562306a36Sopenharmony_ci		return -EINVAL;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	ret = of_gpiochip_add_pin_range(chip);
109862306a36Sopenharmony_ci	if (ret)
109962306a36Sopenharmony_ci		return ret;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	of_node_get(np);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	ret = of_gpiochip_scan_gpios(chip);
110462306a36Sopenharmony_ci	if (ret)
110562306a36Sopenharmony_ci		of_node_put(np);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	return ret;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_civoid of_gpiochip_remove(struct gpio_chip *chip)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	of_node_put(dev_of_node(&chip->gpiodev->dev));
111362306a36Sopenharmony_ci}
1114