13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * OF helpers for the GPIO API
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright (c) 2007-2008  MontaVista Software, Inc.
63d0407baSopenharmony_ci *
73d0407baSopenharmony_ci * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
83d0407baSopenharmony_ci */
93d0407baSopenharmony_ci
103d0407baSopenharmony_ci#include <linux/device.h>
113d0407baSopenharmony_ci#include <linux/err.h>
123d0407baSopenharmony_ci#include <linux/errno.h>
133d0407baSopenharmony_ci#include <linux/module.h>
143d0407baSopenharmony_ci#include <linux/io.h>
153d0407baSopenharmony_ci#include <linux/gpio/consumer.h>
163d0407baSopenharmony_ci#include <linux/of.h>
173d0407baSopenharmony_ci#include <linux/of_address.h>
183d0407baSopenharmony_ci#include <linux/of_gpio.h>
193d0407baSopenharmony_ci#include <linux/pinctrl/pinctrl.h>
203d0407baSopenharmony_ci#include <linux/slab.h>
213d0407baSopenharmony_ci#include <linux/gpio/machine.h>
223d0407baSopenharmony_ci
233d0407baSopenharmony_ci#include "gpiolib.h"
243d0407baSopenharmony_ci#include "gpiolib-of.h"
253d0407baSopenharmony_ci
263d0407baSopenharmony_ci/**
273d0407baSopenharmony_ci * of_gpio_spi_cs_get_count() - special GPIO counting for SPI
283d0407baSopenharmony_ci * @dev:    Consuming device
293d0407baSopenharmony_ci * @con_id: Function within the GPIO consumer
303d0407baSopenharmony_ci *
313d0407baSopenharmony_ci * Some elder GPIO controllers need special quirks. Currently we handle
323d0407baSopenharmony_ci * the Freescale and PPC GPIO controller with bindings that doesn't use the
333d0407baSopenharmony_ci * established "cs-gpios" for chip selects but instead rely on
343d0407baSopenharmony_ci * "gpios" for the chip select lines. If we detect this, we redirect
353d0407baSopenharmony_ci * the counting of "cs-gpios" to count "gpios" transparent to the
363d0407baSopenharmony_ci * driver.
373d0407baSopenharmony_ci */
383d0407baSopenharmony_cistatic int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
393d0407baSopenharmony_ci{
403d0407baSopenharmony_ci    struct device_node *np = dev->of_node;
413d0407baSopenharmony_ci
423d0407baSopenharmony_ci    if (!IS_ENABLED(CONFIG_SPI_MASTER)) {
433d0407baSopenharmony_ci        return 0;
443d0407baSopenharmony_ci    }
453d0407baSopenharmony_ci    if (!con_id || strcmp(con_id, "cs")) {
463d0407baSopenharmony_ci        return 0;
473d0407baSopenharmony_ci    }
483d0407baSopenharmony_ci    if (!of_device_is_compatible(np, "fsl,spi") && !of_device_is_compatible(np, "aeroflexgaisler,spictrl") &&
493d0407baSopenharmony_ci        !of_device_is_compatible(np, "ibm,ppc4xx-spi")) {
503d0407baSopenharmony_ci        return 0;
513d0407baSopenharmony_ci    }
523d0407baSopenharmony_ci    return of_gpio_named_count(np, "gpios");
533d0407baSopenharmony_ci}
543d0407baSopenharmony_ci
553d0407baSopenharmony_ci/*
563d0407baSopenharmony_ci * This is used by external users of of_gpio_count() from <linux/of_gpio.h>
573d0407baSopenharmony_ci *
583d0407baSopenharmony_ci * get rid of those external users by converting them to GPIO
593d0407baSopenharmony_ci * descriptors and let them all use gpiod_count()
603d0407baSopenharmony_ci */
613d0407baSopenharmony_ciint of_gpio_get_count(struct device *dev, const char *con_id)
623d0407baSopenharmony_ci{
633d0407baSopenharmony_ci    int ret;
643d0407baSopenharmony_ci    char propname[32];
653d0407baSopenharmony_ci    unsigned int i;
663d0407baSopenharmony_ci
673d0407baSopenharmony_ci    ret = of_gpio_spi_cs_get_count(dev, con_id);
683d0407baSopenharmony_ci    if (ret > 0) {
693d0407baSopenharmony_ci        return ret;
703d0407baSopenharmony_ci    }
713d0407baSopenharmony_ci
723d0407baSopenharmony_ci    for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
733d0407baSopenharmony_ci        if (con_id) {
743d0407baSopenharmony_ci            snprintf(propname, sizeof(propname), "%s-%s", con_id, gpio_suffixes[i]);
753d0407baSopenharmony_ci        } else {
763d0407baSopenharmony_ci            snprintf(propname, sizeof(propname), "%s", gpio_suffixes[i]);
773d0407baSopenharmony_ci        }
783d0407baSopenharmony_ci
793d0407baSopenharmony_ci        ret = of_gpio_named_count(dev->of_node, propname);
803d0407baSopenharmony_ci        if (ret > 0) {
813d0407baSopenharmony_ci            break;
823d0407baSopenharmony_ci        }
833d0407baSopenharmony_ci    }
843d0407baSopenharmony_ci    return ret ? ret : -ENOENT;
853d0407baSopenharmony_ci}
863d0407baSopenharmony_ci
873d0407baSopenharmony_cistatic int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
883d0407baSopenharmony_ci{
893d0407baSopenharmony_ci    struct of_phandle_args *gpiospec = data;
903d0407baSopenharmony_ci
913d0407baSopenharmony_ci    return chip->gpiodev->dev.of_node == gpiospec->np && chip->of_xlate && chip->of_xlate(chip, gpiospec, NULL) >= 0;
923d0407baSopenharmony_ci}
933d0407baSopenharmony_ci
943d0407baSopenharmony_cistatic struct gpio_chip *of_find_gpiochip_by_xlate(struct of_phandle_args *gpiospec)
953d0407baSopenharmony_ci{
963d0407baSopenharmony_ci    return gpiochip_find(gpiospec, of_gpiochip_match_node_and_xlate);
973d0407baSopenharmony_ci}
983d0407baSopenharmony_ci
993d0407baSopenharmony_cistatic struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, struct of_phandle_args *gpiospec,
1003d0407baSopenharmony_ci                                                      enum of_gpio_flags *flags)
1013d0407baSopenharmony_ci{
1023d0407baSopenharmony_ci    int ret;
1033d0407baSopenharmony_ci
1043d0407baSopenharmony_ci    if (chip->of_gpio_n_cells != gpiospec->args_count) {
1053d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
1063d0407baSopenharmony_ci    }
1073d0407baSopenharmony_ci
1083d0407baSopenharmony_ci    ret = chip->of_xlate(chip, gpiospec, flags);
1093d0407baSopenharmony_ci    if (ret < 0) {
1103d0407baSopenharmony_ci        return ERR_PTR(ret);
1113d0407baSopenharmony_ci    }
1123d0407baSopenharmony_ci
1133d0407baSopenharmony_ci    return gpiochip_get_desc(chip, ret);
1143d0407baSopenharmony_ci}
1153d0407baSopenharmony_ci
1163d0407baSopenharmony_ci/**
1173d0407baSopenharmony_ci * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
1183d0407baSopenharmony_ci * to set the .valid_mask
1193d0407baSopenharmony_ci * @gc: the target gpio_chip
1203d0407baSopenharmony_ci *
1213d0407baSopenharmony_ci * Return: true if the valid mask needs to be set
1223d0407baSopenharmony_ci */
1233d0407baSopenharmony_cibool of_gpio_need_valid_mask(const struct gpio_chip *gc)
1243d0407baSopenharmony_ci{
1253d0407baSopenharmony_ci    int size;
1263d0407baSopenharmony_ci    struct device_node *np = gc->of_node;
1273d0407baSopenharmony_ci
1283d0407baSopenharmony_ci    size = of_property_count_u32_elems(np, "gpio-reserved-ranges");
1293d0407baSopenharmony_ci    if (size > 0 && size % 2 == 0) {
1303d0407baSopenharmony_ci        return true;
1313d0407baSopenharmony_ci    }
1323d0407baSopenharmony_ci    return false;
1333d0407baSopenharmony_ci}
1343d0407baSopenharmony_ci
1353d0407baSopenharmony_cistatic void of_gpio_flags_quirks(struct device_node *np, const char *propname, enum of_gpio_flags *flags, int index)
1363d0407baSopenharmony_ci{
1373d0407baSopenharmony_ci    /*
1383d0407baSopenharmony_ci     * Some GPIO fixed regulator quirks.
1393d0407baSopenharmony_ci     * Note that active low is the default.
1403d0407baSopenharmony_ci     */
1413d0407baSopenharmony_ci    if (IS_ENABLED(CONFIG_REGULATOR) &&
1423d0407baSopenharmony_ci        (of_device_is_compatible(np, "regulator-fixed") || of_device_is_compatible(np, "reg-fixed-voltage") ||
1433d0407baSopenharmony_ci         (!(strcmp(propname, "enable-gpio") && strcmp(propname, "enable-gpios")) &&
1443d0407baSopenharmony_ci          of_device_is_compatible(np, "regulator-gpio")))) {
1453d0407baSopenharmony_ci        bool active_low = !of_property_read_bool(np, "enable-active-high");
1463d0407baSopenharmony_ci        /*
1473d0407baSopenharmony_ci         * The regulator GPIO handles are specified such that the
1483d0407baSopenharmony_ci         * presence or absence of "enable-active-high" solely controls
1493d0407baSopenharmony_ci         * the polarity of the GPIO line. Any phandle flags must
1503d0407baSopenharmony_ci         * be actively ignored.
1513d0407baSopenharmony_ci         */
1523d0407baSopenharmony_ci        if ((*flags & OF_GPIO_ACTIVE_LOW) && !active_low) {
1533d0407baSopenharmony_ci            pr_warn("%s GPIO handle specifies active low - ignored\n", of_node_full_name(np));
1543d0407baSopenharmony_ci            *flags &= ~OF_GPIO_ACTIVE_LOW;
1553d0407baSopenharmony_ci        }
1563d0407baSopenharmony_ci        if (active_low) {
1573d0407baSopenharmony_ci            *flags |= OF_GPIO_ACTIVE_LOW;
1583d0407baSopenharmony_ci        }
1593d0407baSopenharmony_ci    }
1603d0407baSopenharmony_ci    /*
1613d0407baSopenharmony_ci     * Legacy open drain handling for fixed voltage regulators.
1623d0407baSopenharmony_ci     */
1633d0407baSopenharmony_ci    if (IS_ENABLED(CONFIG_REGULATOR) && of_device_is_compatible(np, "reg-fixed-voltage") &&
1643d0407baSopenharmony_ci        of_property_read_bool(np, "gpio-open-drain")) {
1653d0407baSopenharmony_ci        *flags |= (OF_GPIO_SINGLE_ENDED | OF_GPIO_OPEN_DRAIN);
1663d0407baSopenharmony_ci        pr_info("%s uses legacy open drain flag - update the DTS if you can\n", of_node_full_name(np));
1673d0407baSopenharmony_ci    }
1683d0407baSopenharmony_ci
1693d0407baSopenharmony_ci    /*
1703d0407baSopenharmony_ci     * Legacy handling of SPI active high chip select. If we have a
1713d0407baSopenharmony_ci     * property named "cs-gpios" we need to inspect the child node
1723d0407baSopenharmony_ci     * to determine if the flags should have inverted semantics.
1733d0407baSopenharmony_ci     */
1743d0407baSopenharmony_ci    if (IS_ENABLED(CONFIG_SPI_MASTER) && !strcmp(propname, "cs-gpios") && of_property_read_bool(np, "cs-gpios")) {
1753d0407baSopenharmony_ci        struct device_node *child;
1763d0407baSopenharmony_ci        u32 cs;
1773d0407baSopenharmony_ci        int ret;
1783d0407baSopenharmony_ci
1793d0407baSopenharmony_ci        for_each_child_of_node(np, child)
1803d0407baSopenharmony_ci        {
1813d0407baSopenharmony_ci            ret = of_property_read_u32(child, "reg", &cs);
1823d0407baSopenharmony_ci            if (ret) {
1833d0407baSopenharmony_ci                continue;
1843d0407baSopenharmony_ci            }
1853d0407baSopenharmony_ci            if (cs == index) {
1863d0407baSopenharmony_ci                /*
1873d0407baSopenharmony_ci                 * SPI children have active low chip selects
1883d0407baSopenharmony_ci                 * by default. This can be specified negatively
1893d0407baSopenharmony_ci                 * by just omitting "spi-cs-high" in the
1903d0407baSopenharmony_ci                 * device node, or actively by tagging on
1913d0407baSopenharmony_ci                 * GPIO_ACTIVE_LOW as flag in the device
1923d0407baSopenharmony_ci                 * tree. If the line is simultaneously
1933d0407baSopenharmony_ci                 * tagged as active low in the device tree
1943d0407baSopenharmony_ci                 * and has the "spi-cs-high" set, we get a
1953d0407baSopenharmony_ci                 * conflict and the "spi-cs-high" flag will
1963d0407baSopenharmony_ci                 * take precedence.
1973d0407baSopenharmony_ci                 */
1983d0407baSopenharmony_ci                if (of_property_read_bool(child, "spi-cs-high")) {
1993d0407baSopenharmony_ci                    if (*flags & OF_GPIO_ACTIVE_LOW) {
2003d0407baSopenharmony_ci                        pr_warn("%s GPIO handle specifies active low - ignored\n", of_node_full_name(child));
2013d0407baSopenharmony_ci                        *flags &= ~OF_GPIO_ACTIVE_LOW;
2023d0407baSopenharmony_ci                    }
2033d0407baSopenharmony_ci                } else {
2043d0407baSopenharmony_ci                    if (!(*flags & OF_GPIO_ACTIVE_LOW)) {
2053d0407baSopenharmony_ci                        pr_info("%s enforce active low on chipselect handle\n", of_node_full_name(child));
2063d0407baSopenharmony_ci                    }
2073d0407baSopenharmony_ci                    *flags |= OF_GPIO_ACTIVE_LOW;
2083d0407baSopenharmony_ci                }
2093d0407baSopenharmony_ci                of_node_put(child);
2103d0407baSopenharmony_ci                break;
2113d0407baSopenharmony_ci            }
2123d0407baSopenharmony_ci        }
2133d0407baSopenharmony_ci    }
2143d0407baSopenharmony_ci
2153d0407baSopenharmony_ci    /* Legacy handling of stmmac's active-low PHY reset line */
2163d0407baSopenharmony_ci    if (IS_ENABLED(CONFIG_STMMAC_ETH) && !strcmp(propname, "snps,reset-gpio") &&
2173d0407baSopenharmony_ci        of_property_read_bool(np, "snps,reset-active-low")) {
2183d0407baSopenharmony_ci        *flags |= OF_GPIO_ACTIVE_LOW;
2193d0407baSopenharmony_ci    }
2203d0407baSopenharmony_ci}
2213d0407baSopenharmony_ci
2223d0407baSopenharmony_ci/**
2233d0407baSopenharmony_ci * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API
2243d0407baSopenharmony_ci * @np:        device node to get GPIO from
2253d0407baSopenharmony_ci * @propname:    property name containing gpio specifier(s)
2263d0407baSopenharmony_ci * @index:    index of the GPIO
2273d0407baSopenharmony_ci * @flags:    a flags pointer to fill in
2283d0407baSopenharmony_ci *
2293d0407baSopenharmony_ci * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
2303d0407baSopenharmony_ci * value on the error condition. If @flags is not NULL the function also fills
2313d0407baSopenharmony_ci * in flags for the GPIO.
2323d0407baSopenharmony_ci */
2333d0407baSopenharmony_cistatic struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, const char *propname, int index,
2343d0407baSopenharmony_ci                                                  enum of_gpio_flags *flags)
2353d0407baSopenharmony_ci{
2363d0407baSopenharmony_ci    struct of_phandle_args gpiospec;
2373d0407baSopenharmony_ci    struct gpio_chip *chip;
2383d0407baSopenharmony_ci    struct gpio_desc *desc;
2393d0407baSopenharmony_ci    int ret;
2403d0407baSopenharmony_ci
2413d0407baSopenharmony_ci    ret = of_parse_phandle_with_args_map(np, propname, "gpio", index, &gpiospec);
2423d0407baSopenharmony_ci    if (ret) {
2433d0407baSopenharmony_ci        pr_debug("%s: can't parse '%s' property of node '%pOF[%d]'\n", __func__, propname, np, index);
2443d0407baSopenharmony_ci        return ERR_PTR(ret);
2453d0407baSopenharmony_ci    }
2463d0407baSopenharmony_ci
2473d0407baSopenharmony_ci    chip = of_find_gpiochip_by_xlate(&gpiospec);
2483d0407baSopenharmony_ci    if (!chip) {
2493d0407baSopenharmony_ci        desc = ERR_PTR(-EPROBE_DEFER);
2503d0407baSopenharmony_ci        goto out;
2513d0407baSopenharmony_ci    }
2523d0407baSopenharmony_ci
2533d0407baSopenharmony_ci    desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);
2543d0407baSopenharmony_ci    if (IS_ERR(desc)) {
2553d0407baSopenharmony_ci        goto out;
2563d0407baSopenharmony_ci    }
2573d0407baSopenharmony_ci
2583d0407baSopenharmony_ci    if (flags) {
2593d0407baSopenharmony_ci        of_gpio_flags_quirks(np, propname, flags, index);
2603d0407baSopenharmony_ci    }
2613d0407baSopenharmony_ci
2623d0407baSopenharmony_ci    pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n", __func__, propname, np, index,
2633d0407baSopenharmony_ci             PTR_ERR_OR_ZERO(desc));
2643d0407baSopenharmony_ci
2653d0407baSopenharmony_ciout:
2663d0407baSopenharmony_ci    of_node_put(gpiospec.np);
2673d0407baSopenharmony_ci
2683d0407baSopenharmony_ci    return desc;
2693d0407baSopenharmony_ci}
2703d0407baSopenharmony_ci
2713d0407baSopenharmony_ciint of_get_named_gpio_flags(struct device_node *np, const char *list_name, int index, enum of_gpio_flags *flags)
2723d0407baSopenharmony_ci{
2733d0407baSopenharmony_ci    struct gpio_desc *desc;
2743d0407baSopenharmony_ci
2753d0407baSopenharmony_ci    desc = of_get_named_gpiod_flags(np, list_name, index, flags);
2763d0407baSopenharmony_ci    if (IS_ERR(desc)) {
2773d0407baSopenharmony_ci        return PTR_ERR(desc);
2783d0407baSopenharmony_ci    } else {
2793d0407baSopenharmony_ci        return desc_to_gpio(desc);
2803d0407baSopenharmony_ci    }
2813d0407baSopenharmony_ci}
2823d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
2833d0407baSopenharmony_ci
2843d0407baSopenharmony_ci/**
2853d0407baSopenharmony_ci * gpiod_get_from_of_node() - obtain a GPIO from an OF node
2863d0407baSopenharmony_ci * @node:    handle of the OF node
2873d0407baSopenharmony_ci * @propname:    name of the DT property representing the GPIO
2883d0407baSopenharmony_ci * @index:    index of the GPIO to obtain for the consumer
2893d0407baSopenharmony_ci * @dflags:    GPIO initialization flags
2903d0407baSopenharmony_ci * @label:    label to attach to the requested GPIO
2913d0407baSopenharmony_ci *
2923d0407baSopenharmony_ci * Returns:
2933d0407baSopenharmony_ci * On successful request the GPIO pin is configured in accordance with
2943d0407baSopenharmony_ci * provided @dflags.
2953d0407baSopenharmony_ci *
2963d0407baSopenharmony_ci * In case of error an ERR_PTR() is returned.
2973d0407baSopenharmony_ci */
2983d0407baSopenharmony_cistruct gpio_desc *gpiod_get_from_of_node(struct device_node *node, const char *propname, int index,
2993d0407baSopenharmony_ci                                         enum gpiod_flags dflags, const char *label)
3003d0407baSopenharmony_ci{
3013d0407baSopenharmony_ci    unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
3023d0407baSopenharmony_ci    struct gpio_desc *desc;
3033d0407baSopenharmony_ci    enum of_gpio_flags flags;
3043d0407baSopenharmony_ci    bool active_low = false;
3053d0407baSopenharmony_ci    bool single_ended = false;
3063d0407baSopenharmony_ci    bool open_drain = false;
3073d0407baSopenharmony_ci    bool transitory = false;
3083d0407baSopenharmony_ci    int ret;
3093d0407baSopenharmony_ci
3103d0407baSopenharmony_ci    desc = of_get_named_gpiod_flags(node, propname, index, &flags);
3113d0407baSopenharmony_ci    if (!desc || IS_ERR(desc)) {
3123d0407baSopenharmony_ci        return desc;
3133d0407baSopenharmony_ci    }
3143d0407baSopenharmony_ci
3153d0407baSopenharmony_ci    active_low = flags & OF_GPIO_ACTIVE_LOW;
3163d0407baSopenharmony_ci    single_ended = flags & OF_GPIO_SINGLE_ENDED;
3173d0407baSopenharmony_ci    open_drain = flags & OF_GPIO_OPEN_DRAIN;
3183d0407baSopenharmony_ci    transitory = flags & OF_GPIO_TRANSITORY;
3193d0407baSopenharmony_ci
3203d0407baSopenharmony_ci    ret = gpiod_request(desc, label);
3213d0407baSopenharmony_ci    if (ret == -EBUSY && (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE)) {
3223d0407baSopenharmony_ci        return desc;
3233d0407baSopenharmony_ci    }
3243d0407baSopenharmony_ci    if (ret) {
3253d0407baSopenharmony_ci        return ERR_PTR(ret);
3263d0407baSopenharmony_ci    }
3273d0407baSopenharmony_ci
3283d0407baSopenharmony_ci    if (active_low) {
3293d0407baSopenharmony_ci        lflags |= GPIO_ACTIVE_LOW;
3303d0407baSopenharmony_ci    }
3313d0407baSopenharmony_ci
3323d0407baSopenharmony_ci    if (single_ended) {
3333d0407baSopenharmony_ci        if (open_drain) {
3343d0407baSopenharmony_ci            lflags |= GPIO_OPEN_DRAIN;
3353d0407baSopenharmony_ci        } else {
3363d0407baSopenharmony_ci            lflags |= GPIO_OPEN_SOURCE;
3373d0407baSopenharmony_ci        }
3383d0407baSopenharmony_ci    }
3393d0407baSopenharmony_ci
3403d0407baSopenharmony_ci    if (transitory) {
3413d0407baSopenharmony_ci        lflags |= GPIO_TRANSITORY;
3423d0407baSopenharmony_ci    }
3433d0407baSopenharmony_ci
3443d0407baSopenharmony_ci    if (flags & OF_GPIO_PULL_UP) {
3453d0407baSopenharmony_ci        lflags |= GPIO_PULL_UP;
3463d0407baSopenharmony_ci    }
3473d0407baSopenharmony_ci
3483d0407baSopenharmony_ci    if (flags & OF_GPIO_PULL_DOWN) {
3493d0407baSopenharmony_ci        lflags |= GPIO_PULL_DOWN;
3503d0407baSopenharmony_ci    }
3513d0407baSopenharmony_ci
3523d0407baSopenharmony_ci    ret = gpiod_configure_flags(desc, propname, lflags, dflags);
3533d0407baSopenharmony_ci    if (ret < 0) {
3543d0407baSopenharmony_ci        gpiod_put(desc);
3553d0407baSopenharmony_ci        return ERR_PTR(ret);
3563d0407baSopenharmony_ci    }
3573d0407baSopenharmony_ci
3583d0407baSopenharmony_ci    return desc;
3593d0407baSopenharmony_ci}
3603d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
3613d0407baSopenharmony_ci
3623d0407baSopenharmony_ci/*
3633d0407baSopenharmony_ci * The SPI GPIO bindings happened before we managed to establish that GPIO
3643d0407baSopenharmony_ci * properties should be named "foo-gpios" so we have this special kludge for
3653d0407baSopenharmony_ci * them.
3663d0407baSopenharmony_ci */
3673d0407baSopenharmony_cistatic struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id, enum of_gpio_flags *of_flags)
3683d0407baSopenharmony_ci{
3693d0407baSopenharmony_ci    char prop_name[32]; /* 32 is max size of property name */
3703d0407baSopenharmony_ci    struct device_node *np = dev->of_node;
3713d0407baSopenharmony_ci    struct gpio_desc *desc;
3723d0407baSopenharmony_ci    int ret = 0;
3733d0407baSopenharmony_ci    /*
3743d0407baSopenharmony_ci     * Hopefully the compiler stubs the rest of the function if this
3753d0407baSopenharmony_ci     * is false.
3763d0407baSopenharmony_ci     */
3773d0407baSopenharmony_ci    if (!IS_ENABLED(CONFIG_SPI_MASTER)) {
3783d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
3793d0407baSopenharmony_ci    }
3803d0407baSopenharmony_ci
3813d0407baSopenharmony_ci    /* Allow this specifically for "spi-gpio" devices */
3823d0407baSopenharmony_ci    if (!of_device_is_compatible(np, "spi-gpio") || !con_id) {
3833d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
3843d0407baSopenharmony_ci    }
3853d0407baSopenharmony_ci
3863d0407baSopenharmony_ci    /* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */
3873d0407baSopenharmony_ci    ret = snprintf(prop_name, sizeof(prop_name), "%s-%s", "gpio", con_id);
3883d0407baSopenharmony_ci
3893d0407baSopenharmony_ci    desc = of_get_named_gpiod_flags(np, prop_name, 0, of_flags);
3903d0407baSopenharmony_ci    return desc;
3913d0407baSopenharmony_ci}
3923d0407baSopenharmony_ci
3933d0407baSopenharmony_ci/*
3943d0407baSopenharmony_ci * The old Freescale bindings use simply "gpios" as name for the chip select
3953d0407baSopenharmony_ci * lines rather than "cs-gpios" like all other SPI hardware. Account for this
3963d0407baSopenharmony_ci * with a special quirk.
3973d0407baSopenharmony_ci */
3983d0407baSopenharmony_cistatic struct gpio_desc *of_find_spi_cs_gpio(struct device *dev, const char *con_id, unsigned int idx,
3993d0407baSopenharmony_ci                                             unsigned long *flags)
4003d0407baSopenharmony_ci{
4013d0407baSopenharmony_ci    struct device_node *np = dev->of_node;
4023d0407baSopenharmony_ci
4033d0407baSopenharmony_ci    if (!IS_ENABLED(CONFIG_SPI_MASTER)) {
4043d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4053d0407baSopenharmony_ci    }
4063d0407baSopenharmony_ci
4073d0407baSopenharmony_ci    /* Allow this specifically for Freescale and PPC devices */
4083d0407baSopenharmony_ci    if (!of_device_is_compatible(np, "fsl,spi") && !of_device_is_compatible(np, "aeroflexgaisler,spictrl") &&
4093d0407baSopenharmony_ci        !of_device_is_compatible(np, "ibm,ppc4xx-spi")) {
4103d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4113d0407baSopenharmony_ci    }
4123d0407baSopenharmony_ci    /* Allow only if asking for "cs-gpios" */
4133d0407baSopenharmony_ci    if (!con_id || strcmp(con_id, "cs")) {
4143d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4153d0407baSopenharmony_ci    }
4163d0407baSopenharmony_ci
4173d0407baSopenharmony_ci    /*
4183d0407baSopenharmony_ci     * While all other SPI controllers use "cs-gpios" the Freescale
4193d0407baSopenharmony_ci     * uses just "gpios" so translate to that when "cs-gpios" is
4203d0407baSopenharmony_ci     * requested.
4213d0407baSopenharmony_ci     */
4223d0407baSopenharmony_ci    return of_find_gpio(dev, NULL, idx, flags);
4233d0407baSopenharmony_ci}
4243d0407baSopenharmony_ci
4253d0407baSopenharmony_ci/*
4263d0407baSopenharmony_ci * Some regulator bindings happened before we managed to establish that GPIO
4273d0407baSopenharmony_ci * properties should be named "foo-gpios" so we have this special kludge for
4283d0407baSopenharmony_ci * them.
4293d0407baSopenharmony_ci */
4303d0407baSopenharmony_cistatic struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *con_id, enum of_gpio_flags *of_flags)
4313d0407baSopenharmony_ci{
4323d0407baSopenharmony_ci    /* These are the connection IDs we accept as legacy GPIO phandles */
4333d0407baSopenharmony_ci    const char *whitelist[] = {
4343d0407baSopenharmony_ci        "wlf,ldoena",  /* Arizona */
4353d0407baSopenharmony_ci        "wlf,ldo1ena", /* WM8994 */
4363d0407baSopenharmony_ci        "wlf,ldo2ena", /* WM8994 */
4373d0407baSopenharmony_ci    };
4383d0407baSopenharmony_ci    struct device_node *np = dev->of_node;
4393d0407baSopenharmony_ci    struct gpio_desc *desc;
4403d0407baSopenharmony_ci    int i;
4413d0407baSopenharmony_ci
4423d0407baSopenharmony_ci    if (!IS_ENABLED(CONFIG_REGULATOR)) {
4433d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4443d0407baSopenharmony_ci    }
4453d0407baSopenharmony_ci
4463d0407baSopenharmony_ci    if (!con_id) {
4473d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4483d0407baSopenharmony_ci    }
4493d0407baSopenharmony_ci
4503d0407baSopenharmony_ci    i = match_string(whitelist, ARRAY_SIZE(whitelist), con_id);
4513d0407baSopenharmony_ci    if (i < 0) {
4523d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4533d0407baSopenharmony_ci    }
4543d0407baSopenharmony_ci
4553d0407baSopenharmony_ci    desc = of_get_named_gpiod_flags(np, con_id, 0, of_flags);
4563d0407baSopenharmony_ci    return desc;
4573d0407baSopenharmony_ci}
4583d0407baSopenharmony_ci
4593d0407baSopenharmony_cistatic struct gpio_desc *of_find_arizona_gpio(struct device *dev, const char *con_id, enum of_gpio_flags *of_flags)
4603d0407baSopenharmony_ci{
4613d0407baSopenharmony_ci    if (!IS_ENABLED(CONFIG_MFD_ARIZONA)) {
4623d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4633d0407baSopenharmony_ci    }
4643d0407baSopenharmony_ci
4653d0407baSopenharmony_ci    if (!con_id || strcmp(con_id, "wlf,reset")) {
4663d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4673d0407baSopenharmony_ci    }
4683d0407baSopenharmony_ci
4693d0407baSopenharmony_ci    return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
4703d0407baSopenharmony_ci}
4713d0407baSopenharmony_ci
4723d0407baSopenharmony_cistatic struct gpio_desc *of_find_usb_gpio(struct device *dev, const char *con_id, enum of_gpio_flags *of_flags)
4733d0407baSopenharmony_ci{
4743d0407baSopenharmony_ci    /*
4753d0407baSopenharmony_ci     * Currently this USB quirk is only for the Fairchild FUSB302 host which is using
4763d0407baSopenharmony_ci     * an undocumented DT GPIO line named "fcs,int_n" without the compulsory "-gpios"
4773d0407baSopenharmony_ci     * suffix.
4783d0407baSopenharmony_ci     */
4793d0407baSopenharmony_ci    if (!IS_ENABLED(CONFIG_TYPEC_FUSB302)) {
4803d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4813d0407baSopenharmony_ci    }
4823d0407baSopenharmony_ci
4833d0407baSopenharmony_ci    if (!con_id || strcmp(con_id, "fcs,int_n")) {
4843d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
4853d0407baSopenharmony_ci    }
4863d0407baSopenharmony_ci
4873d0407baSopenharmony_ci    return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
4883d0407baSopenharmony_ci}
4893d0407baSopenharmony_ci
4903d0407baSopenharmony_cistruct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, unsigned long *flags)
4913d0407baSopenharmony_ci{
4923d0407baSopenharmony_ci    char prop_name[32]; /* 32 is max size of property name */
4933d0407baSopenharmony_ci    enum of_gpio_flags of_flags;
4943d0407baSopenharmony_ci    struct gpio_desc *desc;
4953d0407baSopenharmony_ci    unsigned int i;
4963d0407baSopenharmony_ci
4973d0407baSopenharmony_ci    /* Try GPIO property "foo-gpios" and "foo-gpio" */
4983d0407baSopenharmony_ci    for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
4993d0407baSopenharmony_ci        if (con_id) {
5003d0407baSopenharmony_ci            snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, gpio_suffixes[i]);
5013d0407baSopenharmony_ci        } else {
5023d0407baSopenharmony_ci            snprintf(prop_name, sizeof(prop_name), "%s", gpio_suffixes[i]);
5033d0407baSopenharmony_ci        }
5043d0407baSopenharmony_ci
5053d0407baSopenharmony_ci        desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, &of_flags);
5063d0407baSopenharmony_ci        if (!IS_ERR(desc) || PTR_ERR(desc) != -ENOENT) {
5073d0407baSopenharmony_ci            break;
5083d0407baSopenharmony_ci        }
5093d0407baSopenharmony_ci    }
5103d0407baSopenharmony_ci
5113d0407baSopenharmony_ci    if (PTR_ERR(desc) == -ENOENT) {
5123d0407baSopenharmony_ci        /* Special handling for SPI GPIOs if used */
5133d0407baSopenharmony_ci        desc = of_find_spi_gpio(dev, con_id, &of_flags);
5143d0407baSopenharmony_ci    }
5153d0407baSopenharmony_ci
5163d0407baSopenharmony_ci    if (PTR_ERR(desc) == -ENOENT) {
5173d0407baSopenharmony_ci        /* This quirk looks up flags and all */
5183d0407baSopenharmony_ci        desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
5193d0407baSopenharmony_ci        if (!IS_ERR(desc)) {
5203d0407baSopenharmony_ci            return desc;
5213d0407baSopenharmony_ci        }
5223d0407baSopenharmony_ci    }
5233d0407baSopenharmony_ci
5243d0407baSopenharmony_ci    if (PTR_ERR(desc) == -ENOENT) {
5253d0407baSopenharmony_ci        /* Special handling for regulator GPIOs if used */
5263d0407baSopenharmony_ci        desc = of_find_regulator_gpio(dev, con_id, &of_flags);
5273d0407baSopenharmony_ci    }
5283d0407baSopenharmony_ci
5293d0407baSopenharmony_ci    if (PTR_ERR(desc) == -ENOENT) {
5303d0407baSopenharmony_ci        desc = of_find_arizona_gpio(dev, con_id, &of_flags);
5313d0407baSopenharmony_ci    }
5323d0407baSopenharmony_ci
5333d0407baSopenharmony_ci    if (PTR_ERR(desc) == -ENOENT) {
5343d0407baSopenharmony_ci        desc = of_find_usb_gpio(dev, con_id, &of_flags);
5353d0407baSopenharmony_ci    }
5363d0407baSopenharmony_ci
5373d0407baSopenharmony_ci    if (IS_ERR(desc)) {
5383d0407baSopenharmony_ci        return desc;
5393d0407baSopenharmony_ci    }
5403d0407baSopenharmony_ci
5413d0407baSopenharmony_ci    if (of_flags & OF_GPIO_ACTIVE_LOW) {
5423d0407baSopenharmony_ci        *flags |= GPIO_ACTIVE_LOW;
5433d0407baSopenharmony_ci    }
5443d0407baSopenharmony_ci
5453d0407baSopenharmony_ci    if (of_flags & OF_GPIO_SINGLE_ENDED) {
5463d0407baSopenharmony_ci        if (of_flags & OF_GPIO_OPEN_DRAIN) {
5473d0407baSopenharmony_ci            *flags |= GPIO_OPEN_DRAIN;
5483d0407baSopenharmony_ci        } else {
5493d0407baSopenharmony_ci            *flags |= GPIO_OPEN_SOURCE;
5503d0407baSopenharmony_ci        }
5513d0407baSopenharmony_ci    }
5523d0407baSopenharmony_ci
5533d0407baSopenharmony_ci    if (of_flags & OF_GPIO_TRANSITORY) {
5543d0407baSopenharmony_ci        *flags |= GPIO_TRANSITORY;
5553d0407baSopenharmony_ci    }
5563d0407baSopenharmony_ci
5573d0407baSopenharmony_ci    if (of_flags & OF_GPIO_PULL_UP) {
5583d0407baSopenharmony_ci        *flags |= GPIO_PULL_UP;
5593d0407baSopenharmony_ci    }
5603d0407baSopenharmony_ci    if (of_flags & OF_GPIO_PULL_DOWN) {
5613d0407baSopenharmony_ci        *flags |= GPIO_PULL_DOWN;
5623d0407baSopenharmony_ci    }
5633d0407baSopenharmony_ci
5643d0407baSopenharmony_ci    return desc;
5653d0407baSopenharmony_ci}
5663d0407baSopenharmony_ci
5673d0407baSopenharmony_ci/**
5683d0407baSopenharmony_ci * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API
5693d0407baSopenharmony_ci * @np:        device node to get GPIO from
5703d0407baSopenharmony_ci * @chip:    GPIO chip whose hog is parsed
5713d0407baSopenharmony_ci * @idx:    Index of the GPIO to parse
5723d0407baSopenharmony_ci * @name:    GPIO line name
5733d0407baSopenharmony_ci * @lflags:    bitmask of gpio_lookup_flags GPIO_* values - returned from
5743d0407baSopenharmony_ci *        of_find_gpio() or of_parse_own_gpio()
5753d0407baSopenharmony_ci * @dflags:    gpiod_flags - optional GPIO initialization flags
5763d0407baSopenharmony_ci *
5773d0407baSopenharmony_ci * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
5783d0407baSopenharmony_ci * value on the error condition.
5793d0407baSopenharmony_ci */
5803d0407baSopenharmony_cistatic struct gpio_desc *of_parse_own_gpio(struct device_node *np, struct gpio_chip *chip, unsigned int idx,
5813d0407baSopenharmony_ci                                           const char **name, unsigned long *lflags, enum gpiod_flags *dflags)
5823d0407baSopenharmony_ci{
5833d0407baSopenharmony_ci    struct device_node *chip_np;
5843d0407baSopenharmony_ci    enum of_gpio_flags xlate_flags;
5853d0407baSopenharmony_ci    struct of_phandle_args gpiospec;
5863d0407baSopenharmony_ci    struct gpio_desc *desc;
5873d0407baSopenharmony_ci    unsigned int i;
5883d0407baSopenharmony_ci    u32 tmp;
5893d0407baSopenharmony_ci    int ret;
5903d0407baSopenharmony_ci
5913d0407baSopenharmony_ci    chip_np = chip->of_node;
5923d0407baSopenharmony_ci    if (!chip_np) {
5933d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
5943d0407baSopenharmony_ci    }
5953d0407baSopenharmony_ci
5963d0407baSopenharmony_ci    xlate_flags = 0;
5973d0407baSopenharmony_ci    *lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
5983d0407baSopenharmony_ci    *dflags = 0;
5993d0407baSopenharmony_ci
6003d0407baSopenharmony_ci    ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
6013d0407baSopenharmony_ci    if (ret) {
6023d0407baSopenharmony_ci        return ERR_PTR(ret);
6033d0407baSopenharmony_ci    }
6043d0407baSopenharmony_ci
6053d0407baSopenharmony_ci    gpiospec.np = chip_np;
6063d0407baSopenharmony_ci    gpiospec.args_count = tmp;
6073d0407baSopenharmony_ci
6083d0407baSopenharmony_ci    for (i = 0; i < tmp; i++) {
6093d0407baSopenharmony_ci        ret = of_property_read_u32_index(np, "gpios", idx * tmp + i, &gpiospec.args[i]);
6103d0407baSopenharmony_ci        if (ret) {
6113d0407baSopenharmony_ci            return ERR_PTR(ret);
6123d0407baSopenharmony_ci        }
6133d0407baSopenharmony_ci    }
6143d0407baSopenharmony_ci
6153d0407baSopenharmony_ci    desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, &xlate_flags);
6163d0407baSopenharmony_ci    if (IS_ERR(desc)) {
6173d0407baSopenharmony_ci        return desc;
6183d0407baSopenharmony_ci    }
6193d0407baSopenharmony_ci
6203d0407baSopenharmony_ci    if (xlate_flags & OF_GPIO_ACTIVE_LOW) {
6213d0407baSopenharmony_ci        *lflags |= GPIO_ACTIVE_LOW;
6223d0407baSopenharmony_ci    }
6233d0407baSopenharmony_ci    if (xlate_flags & OF_GPIO_TRANSITORY) {
6243d0407baSopenharmony_ci        *lflags |= GPIO_TRANSITORY;
6253d0407baSopenharmony_ci    }
6263d0407baSopenharmony_ci    if (xlate_flags & OF_GPIO_PULL_UP) {
6273d0407baSopenharmony_ci        *lflags |= GPIO_PULL_UP;
6283d0407baSopenharmony_ci    }
6293d0407baSopenharmony_ci    if (xlate_flags & OF_GPIO_PULL_DOWN) {
6303d0407baSopenharmony_ci        *lflags |= GPIO_PULL_DOWN;
6313d0407baSopenharmony_ci    }
6323d0407baSopenharmony_ci
6333d0407baSopenharmony_ci    if (of_property_read_bool(np, "input")) {
6343d0407baSopenharmony_ci        *dflags |= GPIOD_IN;
6353d0407baSopenharmony_ci    } else if (of_property_read_bool(np, "output-low")) {
6363d0407baSopenharmony_ci        *dflags |= GPIOD_OUT_LOW;
6373d0407baSopenharmony_ci    } else if (of_property_read_bool(np, "output-high")) {
6383d0407baSopenharmony_ci        *dflags |= GPIOD_OUT_HIGH;
6393d0407baSopenharmony_ci    } else {
6403d0407baSopenharmony_ci        pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n", desc_to_gpio(desc), np);
6413d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
6423d0407baSopenharmony_ci    }
6433d0407baSopenharmony_ci
6443d0407baSopenharmony_ci    if (name && of_property_read_string(np, "line-name", name)) {
6453d0407baSopenharmony_ci        *name = np->name;
6463d0407baSopenharmony_ci    }
6473d0407baSopenharmony_ci
6483d0407baSopenharmony_ci    return desc;
6493d0407baSopenharmony_ci}
6503d0407baSopenharmony_ci
6513d0407baSopenharmony_ci/**
6523d0407baSopenharmony_ci * of_gpiochip_add_hog - Add all hogs in a hog device node
6533d0407baSopenharmony_ci * @chip:    gpio chip to act on
6543d0407baSopenharmony_ci * @hog:    device node describing the hogs
6553d0407baSopenharmony_ci *
6563d0407baSopenharmony_ci * Returns error if it fails otherwise 0 on success.
6573d0407baSopenharmony_ci */
6583d0407baSopenharmony_cistatic int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
6593d0407baSopenharmony_ci{
6603d0407baSopenharmony_ci    enum gpiod_flags dflags;
6613d0407baSopenharmony_ci    struct gpio_desc *desc;
6623d0407baSopenharmony_ci    unsigned long lflags;
6633d0407baSopenharmony_ci    const char *name;
6643d0407baSopenharmony_ci    unsigned int i;
6653d0407baSopenharmony_ci    int ret;
6663d0407baSopenharmony_ci
6673d0407baSopenharmony_ci    for (i = 0;; i++) {
6683d0407baSopenharmony_ci        desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags);
6693d0407baSopenharmony_ci        if (IS_ERR(desc)) {
6703d0407baSopenharmony_ci            break;
6713d0407baSopenharmony_ci        }
6723d0407baSopenharmony_ci
6733d0407baSopenharmony_ci        ret = gpiod_hog(desc, name, lflags, dflags);
6743d0407baSopenharmony_ci        if (ret < 0) {
6753d0407baSopenharmony_ci            return ret;
6763d0407baSopenharmony_ci        }
6773d0407baSopenharmony_ci
6783d0407baSopenharmony_ci#ifdef CONFIG_OF_DYNAMIC
6793d0407baSopenharmony_ci        desc->hog = hog;
6803d0407baSopenharmony_ci#endif
6813d0407baSopenharmony_ci    }
6823d0407baSopenharmony_ci
6833d0407baSopenharmony_ci    return 0;
6843d0407baSopenharmony_ci}
6853d0407baSopenharmony_ci
6863d0407baSopenharmony_ci/**
6873d0407baSopenharmony_ci * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
6883d0407baSopenharmony_ci * @chip:    gpio chip to act on
6893d0407baSopenharmony_ci *
6903d0407baSopenharmony_ci * This is only used by of_gpiochip_add to request/set GPIO initial
6913d0407baSopenharmony_ci * configuration.
6923d0407baSopenharmony_ci * It returns error if it fails otherwise 0 on success.
6933d0407baSopenharmony_ci */
6943d0407baSopenharmony_cistatic int of_gpiochip_scan_gpios(struct gpio_chip *chip)
6953d0407baSopenharmony_ci{
6963d0407baSopenharmony_ci    struct device_node *np;
6973d0407baSopenharmony_ci    int ret;
6983d0407baSopenharmony_ci
6993d0407baSopenharmony_ci    for_each_available_child_of_node(chip->of_node, np)
7003d0407baSopenharmony_ci    {
7013d0407baSopenharmony_ci        if (!of_property_read_bool(np, "gpio-hog")) {
7023d0407baSopenharmony_ci            continue;
7033d0407baSopenharmony_ci        }
7043d0407baSopenharmony_ci
7053d0407baSopenharmony_ci        ret = of_gpiochip_add_hog(chip, np);
7063d0407baSopenharmony_ci        if (ret < 0) {
7073d0407baSopenharmony_ci            of_node_put(np);
7083d0407baSopenharmony_ci            return ret;
7093d0407baSopenharmony_ci        }
7103d0407baSopenharmony_ci
7113d0407baSopenharmony_ci        of_node_set_flag(np, OF_POPULATED);
7123d0407baSopenharmony_ci    }
7133d0407baSopenharmony_ci
7143d0407baSopenharmony_ci    return 0;
7153d0407baSopenharmony_ci}
7163d0407baSopenharmony_ci
7173d0407baSopenharmony_ci#ifdef CONFIG_OF_DYNAMIC
7183d0407baSopenharmony_ci/**
7193d0407baSopenharmony_ci * of_gpiochip_remove_hog - Remove all hogs in a hog device node
7203d0407baSopenharmony_ci * @chip:    gpio chip to act on
7213d0407baSopenharmony_ci * @hog:    device node describing the hogs
7223d0407baSopenharmony_ci */
7233d0407baSopenharmony_cistatic void of_gpiochip_remove_hog(struct gpio_chip *chip, struct device_node *hog)
7243d0407baSopenharmony_ci{
7253d0407baSopenharmony_ci    struct gpio_desc *descs = chip->gpiodev->descs;
7263d0407baSopenharmony_ci    unsigned int i;
7273d0407baSopenharmony_ci
7283d0407baSopenharmony_ci    for (i = 0; i < chip->ngpio; i++) {
7293d0407baSopenharmony_ci        if (test_bit(FLAG_IS_HOGGED, &descs[i].flags) && descs[i].hog == hog) {
7303d0407baSopenharmony_ci            gpiochip_free_own_desc(&descs[i]);
7313d0407baSopenharmony_ci        }
7323d0407baSopenharmony_ci    }
7333d0407baSopenharmony_ci}
7343d0407baSopenharmony_ci
7353d0407baSopenharmony_cistatic int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
7363d0407baSopenharmony_ci{
7373d0407baSopenharmony_ci    return chip->gpiodev->dev.of_node == data;
7383d0407baSopenharmony_ci}
7393d0407baSopenharmony_ci
7403d0407baSopenharmony_cistatic struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
7413d0407baSopenharmony_ci{
7423d0407baSopenharmony_ci    return gpiochip_find(np, of_gpiochip_match_node);
7433d0407baSopenharmony_ci}
7443d0407baSopenharmony_ci
7453d0407baSopenharmony_cistatic int of_gpio_notify(struct notifier_block *nb, unsigned long action, void *arg)
7463d0407baSopenharmony_ci{
7473d0407baSopenharmony_ci    struct of_reconfig_data *rd = arg;
7483d0407baSopenharmony_ci    struct gpio_chip *chip;
7493d0407baSopenharmony_ci    int ret;
7503d0407baSopenharmony_ci
7513d0407baSopenharmony_ci    /*
7523d0407baSopenharmony_ci     * This only supports adding and removing complete gpio-hog nodes.
7533d0407baSopenharmony_ci     * Modifying an existing gpio-hog node is not supported (except for
7543d0407baSopenharmony_ci     * changing its "status" property, which is treated the same as
7553d0407baSopenharmony_ci     * addition/removal).
7563d0407baSopenharmony_ci     */
7573d0407baSopenharmony_ci    switch (of_reconfig_get_state_change(action, arg)) {
7583d0407baSopenharmony_ci        case OF_RECONFIG_CHANGE_ADD:
7593d0407baSopenharmony_ci            if (!of_property_read_bool(rd->dn, "gpio-hog")) {
7603d0407baSopenharmony_ci                return NOTIFY_OK; /* not for us */
7613d0407baSopenharmony_ci            }
7623d0407baSopenharmony_ci
7633d0407baSopenharmony_ci            if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) {
7643d0407baSopenharmony_ci                return NOTIFY_OK;
7653d0407baSopenharmony_ci            }
7663d0407baSopenharmony_ci
7673d0407baSopenharmony_ci            chip = of_find_gpiochip_by_node(rd->dn->parent);
7683d0407baSopenharmony_ci            if (chip == NULL) {
7693d0407baSopenharmony_ci                return NOTIFY_OK; /* not for us */
7703d0407baSopenharmony_ci            }
7713d0407baSopenharmony_ci
7723d0407baSopenharmony_ci            ret = of_gpiochip_add_hog(chip, rd->dn);
7733d0407baSopenharmony_ci            if (ret < 0) {
7743d0407baSopenharmony_ci                pr_err("%s: failed to add hogs for %pOF\n", __func__, rd->dn);
7753d0407baSopenharmony_ci                of_node_clear_flag(rd->dn, OF_POPULATED);
7763d0407baSopenharmony_ci                return notifier_from_errno(ret);
7773d0407baSopenharmony_ci            }
7783d0407baSopenharmony_ci            break;
7793d0407baSopenharmony_ci
7803d0407baSopenharmony_ci        case OF_RECONFIG_CHANGE_REMOVE:
7813d0407baSopenharmony_ci            if (!of_node_check_flag(rd->dn, OF_POPULATED)) {
7823d0407baSopenharmony_ci                return NOTIFY_OK; /* already depopulated */
7833d0407baSopenharmony_ci            }
7843d0407baSopenharmony_ci
7853d0407baSopenharmony_ci            chip = of_find_gpiochip_by_node(rd->dn->parent);
7863d0407baSopenharmony_ci            if (chip == NULL) {
7873d0407baSopenharmony_ci                return NOTIFY_OK; /* not for us */
7883d0407baSopenharmony_ci            }
7893d0407baSopenharmony_ci
7903d0407baSopenharmony_ci            of_gpiochip_remove_hog(chip, rd->dn);
7913d0407baSopenharmony_ci            of_node_clear_flag(rd->dn, OF_POPULATED);
7923d0407baSopenharmony_ci            break;
7933d0407baSopenharmony_ci    }
7943d0407baSopenharmony_ci
7953d0407baSopenharmony_ci    return NOTIFY_OK;
7963d0407baSopenharmony_ci}
7973d0407baSopenharmony_ci
7983d0407baSopenharmony_cistruct notifier_block gpio_of_notifier = {
7993d0407baSopenharmony_ci    .notifier_call = of_gpio_notify,
8003d0407baSopenharmony_ci};
8013d0407baSopenharmony_ci#endif /* CONFIG_OF_DYNAMIC */
8023d0407baSopenharmony_ci
8033d0407baSopenharmony_ci/**
8043d0407baSopenharmony_ci * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
8053d0407baSopenharmony_ci * @gc:        pointer to the gpio_chip structure
8063d0407baSopenharmony_ci * @gpiospec:    GPIO specifier as found in the device tree
8073d0407baSopenharmony_ci * @flags:    a flags pointer to fill in
8083d0407baSopenharmony_ci *
8093d0407baSopenharmony_ci * This is simple translation function, suitable for the most 1:1 mapped
8103d0407baSopenharmony_ci * GPIO chips. This function performs only one sanity check: whether GPIO
8113d0407baSopenharmony_ci * is less than ngpios (that is specified in the gpio_chip).
8123d0407baSopenharmony_ci */
8133d0407baSopenharmony_cistatic int of_gpio_simple_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags)
8143d0407baSopenharmony_ci{
8153d0407baSopenharmony_ci    /*
8163d0407baSopenharmony_ci     * We're discouraging gpio_cells < 2, since that way you'll have to
8173d0407baSopenharmony_ci     * write your own xlate function (that will have to retrieve the GPIO
8183d0407baSopenharmony_ci     * number and the flags from a single gpio cell -- this is possible,
8193d0407baSopenharmony_ci     * but not recommended).
8203d0407baSopenharmony_ci     */
8213d0407baSopenharmony_ci    if (gc->of_gpio_n_cells < 2) {
8223d0407baSopenharmony_ci        WARN_ON(1);
8233d0407baSopenharmony_ci        return -EINVAL;
8243d0407baSopenharmony_ci    }
8253d0407baSopenharmony_ci
8263d0407baSopenharmony_ci    if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) {
8273d0407baSopenharmony_ci        return -EINVAL;
8283d0407baSopenharmony_ci    }
8293d0407baSopenharmony_ci
8303d0407baSopenharmony_ci    if (gpiospec->args[0] >= gc->ngpio) {
8313d0407baSopenharmony_ci        return -EINVAL;
8323d0407baSopenharmony_ci    }
8333d0407baSopenharmony_ci
8343d0407baSopenharmony_ci    if (flags) {
8353d0407baSopenharmony_ci        *flags = gpiospec->args[1];
8363d0407baSopenharmony_ci    }
8373d0407baSopenharmony_ci
8383d0407baSopenharmony_ci    return gpiospec->args[0];
8393d0407baSopenharmony_ci}
8403d0407baSopenharmony_ci
8413d0407baSopenharmony_ci/**
8423d0407baSopenharmony_ci * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
8433d0407baSopenharmony_ci * @np:        device node of the GPIO chip
8443d0407baSopenharmony_ci * @mm_gc:    pointer to the of_mm_gpio_chip allocated structure
8453d0407baSopenharmony_ci * @data:    driver data to store in the struct gpio_chip
8463d0407baSopenharmony_ci *
8473d0407baSopenharmony_ci * To use this function you should allocate and fill mm_gc with:
8483d0407baSopenharmony_ci *
8493d0407baSopenharmony_ci * 1) In the gpio_chip structure:
8503d0407baSopenharmony_ci *    - all the callbacks
8513d0407baSopenharmony_ci *    - of_gpio_n_cells
8523d0407baSopenharmony_ci *    - of_xlate callback (optional)
8533d0407baSopenharmony_ci *
8543d0407baSopenharmony_ci * 3) In the of_mm_gpio_chip structure:
8553d0407baSopenharmony_ci *    - save_regs callback (optional)
8563d0407baSopenharmony_ci *
8573d0407baSopenharmony_ci * If succeeded, this function will map bank's memory and will
8583d0407baSopenharmony_ci * do all necessary work for you. Then you'll able to use .regs
8593d0407baSopenharmony_ci * to manage GPIOs from the callbacks.
8603d0407baSopenharmony_ci */
8613d0407baSopenharmony_ciint of_mm_gpiochip_add_data(struct device_node *np, struct of_mm_gpio_chip *mm_gc, void *data)
8623d0407baSopenharmony_ci{
8633d0407baSopenharmony_ci    int ret = -ENOMEM;
8643d0407baSopenharmony_ci    struct gpio_chip *gc = &mm_gc->gc;
8653d0407baSopenharmony_ci    gc->label = kasprintf(GFP_KERNEL, "%pOF", np);
8663d0407baSopenharmony_ci    if (!gc->label) {
8673d0407baSopenharmony_ci        goto err0;
8683d0407baSopenharmony_ci    }
8693d0407baSopenharmony_ci    mm_gc->regs = of_iomap(np, 0);
8703d0407baSopenharmony_ci    if (!mm_gc->regs) {
8713d0407baSopenharmony_ci        goto err1;
8723d0407baSopenharmony_ci    }
8733d0407baSopenharmony_ci    gc->base = -1;
8743d0407baSopenharmony_ci    if (mm_gc->save_regs) {
8753d0407baSopenharmony_ci        mm_gc->save_regs(mm_gc);
8763d0407baSopenharmony_ci    }
8773d0407baSopenharmony_ci        of_node_put(mm_gc->gc.of_node);
8783d0407baSopenharmony_ci    mm_gc->gc.of_node = of_node_get(np);
8793d0407baSopenharmony_ci    ret = gpiochip_add_data(gc, data);
8803d0407baSopenharmony_ci    if (ret) {
8813d0407baSopenharmony_ci        goto err2;
8823d0407baSopenharmony_ci    }
8833d0407baSopenharmony_ci
8843d0407baSopenharmony_ci    return 0;
8853d0407baSopenharmony_cierr2:
8863d0407baSopenharmony_ci    of_node_put(np);
8873d0407baSopenharmony_ci    iounmap(mm_gc->regs);
8883d0407baSopenharmony_cierr1:
8893d0407baSopenharmony_ci    kfree(gc->label);
8903d0407baSopenharmony_cierr0:
8913d0407baSopenharmony_ci    pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret);
8923d0407baSopenharmony_ci    return ret;
8933d0407baSopenharmony_ci}
8943d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data);
8953d0407baSopenharmony_ci
8963d0407baSopenharmony_ci/**
8973d0407baSopenharmony_ci * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
8983d0407baSopenharmony_ci * @mm_gc:    pointer to the of_mm_gpio_chip allocated structure
8993d0407baSopenharmony_ci */
9003d0407baSopenharmony_civoid of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
9013d0407baSopenharmony_ci{
9023d0407baSopenharmony_ci    struct gpio_chip *gc = &mm_gc->gc;
9033d0407baSopenharmony_ci
9043d0407baSopenharmony_ci    if (!mm_gc) {
9053d0407baSopenharmony_ci        return;
9063d0407baSopenharmony_ci    }
9073d0407baSopenharmony_ci
9083d0407baSopenharmony_ci    gpiochip_remove(gc);
9093d0407baSopenharmony_ci    iounmap(mm_gc->regs);
9103d0407baSopenharmony_ci    kfree(gc->label);
9113d0407baSopenharmony_ci}
9123d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
9133d0407baSopenharmony_ci
9143d0407baSopenharmony_cistatic void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
9153d0407baSopenharmony_ci{
9163d0407baSopenharmony_ci    int len, i;
9173d0407baSopenharmony_ci    u32 start, count;
9183d0407baSopenharmony_ci    struct device_node *np = chip->of_node;
9193d0407baSopenharmony_ci
9203d0407baSopenharmony_ci    len = of_property_count_u32_elems(np, "gpio-reserved-ranges");
9213d0407baSopenharmony_ci    if (len < 0 || len % 0x2 != 0) {
9223d0407baSopenharmony_ci        return;
9233d0407baSopenharmony_ci    }
9243d0407baSopenharmony_ci
9253d0407baSopenharmony_ci    for (i = 0; i < len; i += 0x2) {
9263d0407baSopenharmony_ci        of_property_read_u32_index(np, "gpio-reserved-ranges", i, &start);
9273d0407baSopenharmony_ci        of_property_read_u32_index(np, "gpio-reserved-ranges", i + 1, &count);
9283d0407baSopenharmony_ci        if (start >= chip->ngpio || start + count > chip->ngpio) {
9293d0407baSopenharmony_ci            continue;
9303d0407baSopenharmony_ci        }
9313d0407baSopenharmony_ci
9323d0407baSopenharmony_ci        bitmap_clear(chip->valid_mask, start, count);
9333d0407baSopenharmony_ci    }
9343d0407baSopenharmony_ci};
9353d0407baSopenharmony_ci
9363d0407baSopenharmony_ci#ifdef CONFIG_PINCTRL
9373d0407baSopenharmony_cistatic int of_gpiochip_add_pin_range(struct gpio_chip *chip)
9383d0407baSopenharmony_ci{
9393d0407baSopenharmony_ci    struct of_phandle_args pinspec;
9403d0407baSopenharmony_ci    struct pinctrl_dev *pctldev;
9413d0407baSopenharmony_ci    struct device_node *np = chip->of_node;
9423d0407baSopenharmony_ci    int index = 0, ret;
9433d0407baSopenharmony_ci    struct property *group_names;
9443d0407baSopenharmony_ci    static const char group_names_propname[] = "gpio-ranges-group-names";
9453d0407baSopenharmony_ci    const char *name;
9463d0407baSopenharmony_ci
9473d0407baSopenharmony_ci    if (!np) {
9483d0407baSopenharmony_ci        return 0;
9493d0407baSopenharmony_ci    }
9503d0407baSopenharmony_ci
9513d0407baSopenharmony_ci    if (!of_property_read_bool(np, "gpio-ranges") &&
9523d0407baSopenharmony_ci        chip->of_gpio_ranges_fallback) {
9533d0407baSopenharmony_ci        return chip->of_gpio_ranges_fallback(chip, np);
9543d0407baSopenharmony_ci    }
9553d0407baSopenharmony_ci
9563d0407baSopenharmony_ci    group_names = of_find_property(np, group_names_propname, NULL);
9573d0407baSopenharmony_ci
9583d0407baSopenharmony_ci    for (;; index++) {
9593d0407baSopenharmony_ci        ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 0x3, index, &pinspec);
9603d0407baSopenharmony_ci        if (ret) {
9613d0407baSopenharmony_ci            break;
9623d0407baSopenharmony_ci        }
9633d0407baSopenharmony_ci
9643d0407baSopenharmony_ci        pctldev = of_pinctrl_get(pinspec.np);
9653d0407baSopenharmony_ci        of_node_put(pinspec.np);
9663d0407baSopenharmony_ci        if (!pctldev) {
9673d0407baSopenharmony_ci            return -EPROBE_DEFER;
9683d0407baSopenharmony_ci        }
9693d0407baSopenharmony_ci
9703d0407baSopenharmony_ci        if (pinspec.args[0x2]) {
9713d0407baSopenharmony_ci            if (group_names) {
9723d0407baSopenharmony_ci                of_property_read_string_index(np, group_names_propname, index, &name);
9733d0407baSopenharmony_ci                if (strlen(name)) {
9743d0407baSopenharmony_ci                    pr_err("%pOF: Group name of numeric GPIO ranges must be the empty string.\n", np);
9753d0407baSopenharmony_ci                    break;
9763d0407baSopenharmony_ci                }
9773d0407baSopenharmony_ci            }
9783d0407baSopenharmony_ci            /* npins != 0: linear range */
9793d0407baSopenharmony_ci            ret = gpiochip_add_pin_range(chip, pinctrl_dev_get_devname(pctldev), pinspec.args[0x0], pinspec.args[0x1],
9803d0407baSopenharmony_ci                                         pinspec.args[0x2]);
9813d0407baSopenharmony_ci            if (ret) {
9823d0407baSopenharmony_ci                return ret;
9833d0407baSopenharmony_ci            }
9843d0407baSopenharmony_ci        } else {
9853d0407baSopenharmony_ci            /* npins == 0: special range */
9863d0407baSopenharmony_ci            if (pinspec.args[1]) {
9873d0407baSopenharmony_ci                pr_err("%pOF: Illegal gpio-range format.\n", np);
9883d0407baSopenharmony_ci                break;
9893d0407baSopenharmony_ci            }
9903d0407baSopenharmony_ci
9913d0407baSopenharmony_ci            if (!group_names) {
9923d0407baSopenharmony_ci                pr_err("%pOF: GPIO group range requested but no %s property.\n", np, group_names_propname);
9933d0407baSopenharmony_ci                break;
9943d0407baSopenharmony_ci            }
9953d0407baSopenharmony_ci
9963d0407baSopenharmony_ci            ret = of_property_read_string_index(np, group_names_propname, index, &name);
9973d0407baSopenharmony_ci            if (ret) {
9983d0407baSopenharmony_ci                break;
9993d0407baSopenharmony_ci            }
10003d0407baSopenharmony_ci
10013d0407baSopenharmony_ci            if (!strlen(name)) {
10023d0407baSopenharmony_ci                pr_err("%pOF: Group name of GPIO group range cannot be the empty string.\n", np);
10033d0407baSopenharmony_ci                break;
10043d0407baSopenharmony_ci            }
10053d0407baSopenharmony_ci
10063d0407baSopenharmony_ci            ret = gpiochip_add_pingroup_range(chip, pctldev, pinspec.args[0], name);
10073d0407baSopenharmony_ci            if (ret) {
10083d0407baSopenharmony_ci                return ret;
10093d0407baSopenharmony_ci            }
10103d0407baSopenharmony_ci        }
10113d0407baSopenharmony_ci    }
10123d0407baSopenharmony_ci
10133d0407baSopenharmony_ci    return 0;
10143d0407baSopenharmony_ci}
10153d0407baSopenharmony_ci
10163d0407baSopenharmony_ci#else
10173d0407baSopenharmony_cistatic int of_gpiochip_add_pin_range(struct gpio_chip *chip)
10183d0407baSopenharmony_ci{
10193d0407baSopenharmony_ci    return 0;
10203d0407baSopenharmony_ci}
10213d0407baSopenharmony_ci#endif
10223d0407baSopenharmony_ci
10233d0407baSopenharmony_ciint of_gpiochip_add(struct gpio_chip *chip)
10243d0407baSopenharmony_ci{
10253d0407baSopenharmony_ci    int ret;
10263d0407baSopenharmony_ci
10273d0407baSopenharmony_ci    if (!chip->of_node) {
10283d0407baSopenharmony_ci        return 0;
10293d0407baSopenharmony_ci    }
10303d0407baSopenharmony_ci
10313d0407baSopenharmony_ci    if (!chip->of_xlate) {
10323d0407baSopenharmony_ci        chip->of_gpio_n_cells = 0x2;
10333d0407baSopenharmony_ci        chip->of_xlate = of_gpio_simple_xlate;
10343d0407baSopenharmony_ci    }
10353d0407baSopenharmony_ci
10363d0407baSopenharmony_ci    if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS) {
10373d0407baSopenharmony_ci        return -EINVAL;
10383d0407baSopenharmony_ci    }
10393d0407baSopenharmony_ci
10403d0407baSopenharmony_ci    of_gpiochip_init_valid_mask(chip);
10413d0407baSopenharmony_ci
10423d0407baSopenharmony_ci    ret = of_gpiochip_add_pin_range(chip);
10433d0407baSopenharmony_ci    if (ret) {
10443d0407baSopenharmony_ci        return ret;
10453d0407baSopenharmony_ci    }
10463d0407baSopenharmony_ci
10473d0407baSopenharmony_ci    of_node_get(chip->of_node);
10483d0407baSopenharmony_ci
10493d0407baSopenharmony_ci    ret = of_gpiochip_scan_gpios(chip);
10503d0407baSopenharmony_ci    if (ret) {
10513d0407baSopenharmony_ci        of_node_put(chip->of_node);
10523d0407baSopenharmony_ci    }
10533d0407baSopenharmony_ci
10543d0407baSopenharmony_ci    return ret;
10553d0407baSopenharmony_ci}
10563d0407baSopenharmony_ci
10573d0407baSopenharmony_civoid of_gpiochip_remove(struct gpio_chip *chip)
10583d0407baSopenharmony_ci{
10593d0407baSopenharmony_ci    of_node_put(chip->of_node);
10603d0407baSopenharmony_ci}
10613d0407baSopenharmony_ci
10623d0407baSopenharmony_civoid of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
10633d0407baSopenharmony_ci{
10643d0407baSopenharmony_ci    /* If the gpiochip has an assigned OF node this takes precedence */
10653d0407baSopenharmony_ci    if (gc->of_node) {
10663d0407baSopenharmony_ci        gdev->dev.of_node = gc->of_node;
10673d0407baSopenharmony_ci    } else {
10683d0407baSopenharmony_ci        gc->of_node = gdev->dev.of_node;
10693d0407baSopenharmony_ci    }
10703d0407baSopenharmony_ci    if (gdev->dev.of_node) {
10713d0407baSopenharmony_ci        gdev->dev.fwnode = of_fwnode_handle(gdev->dev.of_node);
10723d0407baSopenharmony_ci    }
10733d0407baSopenharmony_ci}
1074