18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * devres.c - managed gpio resources
48c2ecf20Sopenharmony_ci * This file is based on kernel/irq/devres.c
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (c) 2011 John Crispin <john@phrozen.org>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/gpio.h>
128c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
138c2ecf20Sopenharmony_ci#include <linux/device.h>
148c2ecf20Sopenharmony_ci#include <linux/gfp.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "gpiolib.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic void devm_gpiod_release(struct device *dev, void *res)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct gpio_desc **desc = res;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	gpiod_put(*desc);
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic int devm_gpiod_match(struct device *dev, void *res, void *data)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	struct gpio_desc **this = res, **gpio = data;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	return *this == *gpio;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic void devm_gpiod_release_array(struct device *dev, void *res)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct gpio_descs **descs = res;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	gpiod_put_array(*descs);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int devm_gpiod_match_array(struct device *dev, void *res, void *data)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct gpio_descs **this = res, **gpios = data;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	return *this == *gpios;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/**
478c2ecf20Sopenharmony_ci * devm_gpiod_get - Resource-managed gpiod_get()
488c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
498c2ecf20Sopenharmony_ci * @con_id:	function within the GPIO consumer
508c2ecf20Sopenharmony_ci * @flags:	optional GPIO initialization flags
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci * Managed gpiod_get(). GPIO descriptors returned from this function are
538c2ecf20Sopenharmony_ci * automatically disposed on driver detach. See gpiod_get() for detailed
548c2ecf20Sopenharmony_ci * information about behavior and return values.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
578c2ecf20Sopenharmony_ci					      const char *con_id,
588c2ecf20Sopenharmony_ci					      enum gpiod_flags flags)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	return devm_gpiod_get_index(dev, con_id, 0, flags);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/**
658c2ecf20Sopenharmony_ci * devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
668c2ecf20Sopenharmony_ci * @dev: GPIO consumer
678c2ecf20Sopenharmony_ci * @con_id: function within the GPIO consumer
688c2ecf20Sopenharmony_ci * @flags: optional GPIO initialization flags
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci * Managed gpiod_get_optional(). GPIO descriptors returned from this function
718c2ecf20Sopenharmony_ci * are automatically disposed on driver detach. See gpiod_get_optional() for
728c2ecf20Sopenharmony_ci * detailed information about behavior and return values.
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
758c2ecf20Sopenharmony_ci						       const char *con_id,
768c2ecf20Sopenharmony_ci						       enum gpiod_flags flags)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	return devm_gpiod_get_index_optional(dev, con_id, 0, flags);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_optional);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/**
838c2ecf20Sopenharmony_ci * devm_gpiod_get_index - Resource-managed gpiod_get_index()
848c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
858c2ecf20Sopenharmony_ci * @con_id:	function within the GPIO consumer
868c2ecf20Sopenharmony_ci * @idx:	index of the GPIO to obtain in the consumer
878c2ecf20Sopenharmony_ci * @flags:	optional GPIO initialization flags
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * Managed gpiod_get_index(). GPIO descriptors returned from this function are
908c2ecf20Sopenharmony_ci * automatically disposed on driver detach. See gpiod_get_index() for detailed
918c2ecf20Sopenharmony_ci * information about behavior and return values.
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
948c2ecf20Sopenharmony_ci						    const char *con_id,
958c2ecf20Sopenharmony_ci						    unsigned int idx,
968c2ecf20Sopenharmony_ci						    enum gpiod_flags flags)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct gpio_desc **dr;
998c2ecf20Sopenharmony_ci	struct gpio_desc *desc;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	desc = gpiod_get_index(dev, con_id, idx, flags);
1028c2ecf20Sopenharmony_ci	if (IS_ERR(desc))
1038c2ecf20Sopenharmony_ci		return desc;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/*
1068c2ecf20Sopenharmony_ci	 * For non-exclusive GPIO descriptors, check if this descriptor is
1078c2ecf20Sopenharmony_ci	 * already under resource management by this device.
1088c2ecf20Sopenharmony_ci	 */
1098c2ecf20Sopenharmony_ci	if (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
1108c2ecf20Sopenharmony_ci		struct devres *dres;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		dres = devres_find(dev, devm_gpiod_release,
1138c2ecf20Sopenharmony_ci				   devm_gpiod_match, &desc);
1148c2ecf20Sopenharmony_ci		if (dres)
1158c2ecf20Sopenharmony_ci			return desc;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
1198c2ecf20Sopenharmony_ci			  GFP_KERNEL);
1208c2ecf20Sopenharmony_ci	if (!dr) {
1218c2ecf20Sopenharmony_ci		gpiod_put(desc);
1228c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	*dr = desc;
1268c2ecf20Sopenharmony_ci	devres_add(dev, dr);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return desc;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_index);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/**
1338c2ecf20Sopenharmony_ci * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node
1348c2ecf20Sopenharmony_ci * @dev:	device for lifecycle management
1358c2ecf20Sopenharmony_ci * @node:	handle of the OF node
1368c2ecf20Sopenharmony_ci * @propname:	name of the DT property representing the GPIO
1378c2ecf20Sopenharmony_ci * @index:	index of the GPIO to obtain for the consumer
1388c2ecf20Sopenharmony_ci * @dflags:	GPIO initialization flags
1398c2ecf20Sopenharmony_ci * @label:	label to attach to the requested GPIO
1408c2ecf20Sopenharmony_ci *
1418c2ecf20Sopenharmony_ci * Returns:
1428c2ecf20Sopenharmony_ci * On successful request the GPIO pin is configured in accordance with
1438c2ecf20Sopenharmony_ci * provided @dflags.
1448c2ecf20Sopenharmony_ci *
1458c2ecf20Sopenharmony_ci * In case of error an ERR_PTR() is returned.
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_cistruct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
1488c2ecf20Sopenharmony_ci					      struct device_node *node,
1498c2ecf20Sopenharmony_ci					      const char *propname, int index,
1508c2ecf20Sopenharmony_ci					      enum gpiod_flags dflags,
1518c2ecf20Sopenharmony_ci					      const char *label)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct gpio_desc **dr;
1548c2ecf20Sopenharmony_ci	struct gpio_desc *desc;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
1578c2ecf20Sopenharmony_ci	if (IS_ERR(desc))
1588c2ecf20Sopenharmony_ci		return desc;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/*
1618c2ecf20Sopenharmony_ci	 * For non-exclusive GPIO descriptors, check if this descriptor is
1628c2ecf20Sopenharmony_ci	 * already under resource management by this device.
1638c2ecf20Sopenharmony_ci	 */
1648c2ecf20Sopenharmony_ci	if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
1658c2ecf20Sopenharmony_ci		struct devres *dres;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci		dres = devres_find(dev, devm_gpiod_release,
1688c2ecf20Sopenharmony_ci				   devm_gpiod_match, &desc);
1698c2ecf20Sopenharmony_ci		if (dres)
1708c2ecf20Sopenharmony_ci			return desc;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
1748c2ecf20Sopenharmony_ci			  GFP_KERNEL);
1758c2ecf20Sopenharmony_ci	if (!dr) {
1768c2ecf20Sopenharmony_ci		gpiod_put(desc);
1778c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	*dr = desc;
1818c2ecf20Sopenharmony_ci	devres_add(dev, dr);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	return desc;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/**
1888c2ecf20Sopenharmony_ci * devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node
1898c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
1908c2ecf20Sopenharmony_ci * @fwnode:	firmware node containing GPIO reference
1918c2ecf20Sopenharmony_ci * @con_id:	function within the GPIO consumer
1928c2ecf20Sopenharmony_ci * @index:	index of the GPIO to obtain in the consumer
1938c2ecf20Sopenharmony_ci * @flags:	GPIO initialization flags
1948c2ecf20Sopenharmony_ci * @label:	label to attach to the requested GPIO
1958c2ecf20Sopenharmony_ci *
1968c2ecf20Sopenharmony_ci * GPIO descriptors returned from this function are automatically disposed on
1978c2ecf20Sopenharmony_ci * driver detach.
1988c2ecf20Sopenharmony_ci *
1998c2ecf20Sopenharmony_ci * On successful request the GPIO pin is configured in accordance with
2008c2ecf20Sopenharmony_ci * provided @flags.
2018c2ecf20Sopenharmony_ci */
2028c2ecf20Sopenharmony_cistruct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
2038c2ecf20Sopenharmony_ci					      struct fwnode_handle *fwnode,
2048c2ecf20Sopenharmony_ci					      const char *con_id, int index,
2058c2ecf20Sopenharmony_ci					      enum gpiod_flags flags,
2068c2ecf20Sopenharmony_ci					      const char *label)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct gpio_desc **dr;
2098c2ecf20Sopenharmony_ci	struct gpio_desc *desc;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
2128c2ecf20Sopenharmony_ci			  GFP_KERNEL);
2138c2ecf20Sopenharmony_ci	if (!dr)
2148c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	desc = fwnode_gpiod_get_index(fwnode, con_id, index, flags, label);
2178c2ecf20Sopenharmony_ci	if (IS_ERR(desc)) {
2188c2ecf20Sopenharmony_ci		devres_free(dr);
2198c2ecf20Sopenharmony_ci		return desc;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	*dr = desc;
2238c2ecf20Sopenharmony_ci	devres_add(dev, dr);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return desc;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_fwnode_gpiod_get_index);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/**
2308c2ecf20Sopenharmony_ci * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
2318c2ecf20Sopenharmony_ci * @dev: GPIO consumer
2328c2ecf20Sopenharmony_ci * @con_id: function within the GPIO consumer
2338c2ecf20Sopenharmony_ci * @index: index of the GPIO to obtain in the consumer
2348c2ecf20Sopenharmony_ci * @flags: optional GPIO initialization flags
2358c2ecf20Sopenharmony_ci *
2368c2ecf20Sopenharmony_ci * Managed gpiod_get_index_optional(). GPIO descriptors returned from this
2378c2ecf20Sopenharmony_ci * function are automatically disposed on driver detach. See
2388c2ecf20Sopenharmony_ci * gpiod_get_index_optional() for detailed information about behavior and
2398c2ecf20Sopenharmony_ci * return values.
2408c2ecf20Sopenharmony_ci */
2418c2ecf20Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
2428c2ecf20Sopenharmony_ci							     const char *con_id,
2438c2ecf20Sopenharmony_ci							     unsigned int index,
2448c2ecf20Sopenharmony_ci							     enum gpiod_flags flags)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct gpio_desc *desc;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	desc = devm_gpiod_get_index(dev, con_id, index, flags);
2498c2ecf20Sopenharmony_ci	if (IS_ERR(desc)) {
2508c2ecf20Sopenharmony_ci		if (PTR_ERR(desc) == -ENOENT)
2518c2ecf20Sopenharmony_ci			return NULL;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return desc;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_index_optional);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/**
2598c2ecf20Sopenharmony_ci * devm_gpiod_get_array - Resource-managed gpiod_get_array()
2608c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
2618c2ecf20Sopenharmony_ci * @con_id:	function within the GPIO consumer
2628c2ecf20Sopenharmony_ci * @flags:	optional GPIO initialization flags
2638c2ecf20Sopenharmony_ci *
2648c2ecf20Sopenharmony_ci * Managed gpiod_get_array(). GPIO descriptors returned from this function are
2658c2ecf20Sopenharmony_ci * automatically disposed on driver detach. See gpiod_get_array() for detailed
2668c2ecf20Sopenharmony_ci * information about behavior and return values.
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistruct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
2698c2ecf20Sopenharmony_ci						     const char *con_id,
2708c2ecf20Sopenharmony_ci						     enum gpiod_flags flags)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct gpio_descs **dr;
2738c2ecf20Sopenharmony_ci	struct gpio_descs *descs;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	dr = devres_alloc(devm_gpiod_release_array,
2768c2ecf20Sopenharmony_ci			  sizeof(struct gpio_descs *), GFP_KERNEL);
2778c2ecf20Sopenharmony_ci	if (!dr)
2788c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	descs = gpiod_get_array(dev, con_id, flags);
2818c2ecf20Sopenharmony_ci	if (IS_ERR(descs)) {
2828c2ecf20Sopenharmony_ci		devres_free(dr);
2838c2ecf20Sopenharmony_ci		return descs;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	*dr = descs;
2878c2ecf20Sopenharmony_ci	devres_add(dev, dr);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return descs;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_array);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/**
2948c2ecf20Sopenharmony_ci * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional()
2958c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
2968c2ecf20Sopenharmony_ci * @con_id:	function within the GPIO consumer
2978c2ecf20Sopenharmony_ci * @flags:	optional GPIO initialization flags
2988c2ecf20Sopenharmony_ci *
2998c2ecf20Sopenharmony_ci * Managed gpiod_get_array_optional(). GPIO descriptors returned from this
3008c2ecf20Sopenharmony_ci * function are automatically disposed on driver detach.
3018c2ecf20Sopenharmony_ci * See gpiod_get_array_optional() for detailed information about behavior and
3028c2ecf20Sopenharmony_ci * return values.
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_cistruct gpio_descs *__must_check
3058c2ecf20Sopenharmony_cidevm_gpiod_get_array_optional(struct device *dev, const char *con_id,
3068c2ecf20Sopenharmony_ci			      enum gpiod_flags flags)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	struct gpio_descs *descs;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	descs = devm_gpiod_get_array(dev, con_id, flags);
3118c2ecf20Sopenharmony_ci	if (PTR_ERR(descs) == -ENOENT)
3128c2ecf20Sopenharmony_ci		return NULL;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return descs;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_array_optional);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci/**
3198c2ecf20Sopenharmony_ci * devm_gpiod_put - Resource-managed gpiod_put()
3208c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
3218c2ecf20Sopenharmony_ci * @desc:	GPIO descriptor to dispose of
3228c2ecf20Sopenharmony_ci *
3238c2ecf20Sopenharmony_ci * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or
3248c2ecf20Sopenharmony_ci * devm_gpiod_get_index(). Normally this function will not be called as the GPIO
3258c2ecf20Sopenharmony_ci * will be disposed of by the resource management code.
3268c2ecf20Sopenharmony_ci */
3278c2ecf20Sopenharmony_civoid devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match,
3308c2ecf20Sopenharmony_ci		&desc));
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_put);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci/**
3358c2ecf20Sopenharmony_ci * devm_gpiod_unhinge - Remove resource management from a gpio descriptor
3368c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
3378c2ecf20Sopenharmony_ci * @desc:	GPIO descriptor to remove resource management from
3388c2ecf20Sopenharmony_ci *
3398c2ecf20Sopenharmony_ci * Remove resource management from a GPIO descriptor. This is needed when
3408c2ecf20Sopenharmony_ci * you want to hand over lifecycle management of a descriptor to another
3418c2ecf20Sopenharmony_ci * mechanism.
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_civoid devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	int ret;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(desc))
3498c2ecf20Sopenharmony_ci		return;
3508c2ecf20Sopenharmony_ci	ret = devres_destroy(dev, devm_gpiod_release,
3518c2ecf20Sopenharmony_ci			     devm_gpiod_match, &desc);
3528c2ecf20Sopenharmony_ci	/*
3538c2ecf20Sopenharmony_ci	 * If the GPIO descriptor is requested as nonexclusive, we
3548c2ecf20Sopenharmony_ci	 * may call this function several times on the same descriptor
3558c2ecf20Sopenharmony_ci	 * so it is OK if devres_destroy() returns -ENOENT.
3568c2ecf20Sopenharmony_ci	 */
3578c2ecf20Sopenharmony_ci	if (ret == -ENOENT)
3588c2ecf20Sopenharmony_ci		return;
3598c2ecf20Sopenharmony_ci	/* Anything else we should warn about */
3608c2ecf20Sopenharmony_ci	WARN_ON(ret);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_unhinge);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci/**
3658c2ecf20Sopenharmony_ci * devm_gpiod_put_array - Resource-managed gpiod_put_array()
3668c2ecf20Sopenharmony_ci * @dev:	GPIO consumer
3678c2ecf20Sopenharmony_ci * @descs:	GPIO descriptor array to dispose of
3688c2ecf20Sopenharmony_ci *
3698c2ecf20Sopenharmony_ci * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array().
3708c2ecf20Sopenharmony_ci * Normally this function will not be called as the GPIOs will be disposed of
3718c2ecf20Sopenharmony_ci * by the resource management code.
3728c2ecf20Sopenharmony_ci */
3738c2ecf20Sopenharmony_civoid devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	WARN_ON(devres_release(dev, devm_gpiod_release_array,
3768c2ecf20Sopenharmony_ci			       devm_gpiod_match_array, &descs));
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_put_array);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic void devm_gpio_release(struct device *dev, void *res)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	unsigned *gpio = res;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	gpio_free(*gpio);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int devm_gpio_match(struct device *dev, void *res, void *data)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	unsigned *this = res, *gpio = data;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return *this == *gpio;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci/**
3988c2ecf20Sopenharmony_ci *      devm_gpio_request - request a GPIO for a managed device
3998c2ecf20Sopenharmony_ci *      @dev: device to request the GPIO for
4008c2ecf20Sopenharmony_ci *      @gpio: GPIO to allocate
4018c2ecf20Sopenharmony_ci *      @label: the name of the requested GPIO
4028c2ecf20Sopenharmony_ci *
4038c2ecf20Sopenharmony_ci *      Except for the extra @dev argument, this function takes the
4048c2ecf20Sopenharmony_ci *      same arguments and performs the same function as
4058c2ecf20Sopenharmony_ci *      gpio_request().  GPIOs requested with this function will be
4068c2ecf20Sopenharmony_ci *      automatically freed on driver detach.
4078c2ecf20Sopenharmony_ci *
4088c2ecf20Sopenharmony_ci *      If an GPIO allocated with this function needs to be freed
4098c2ecf20Sopenharmony_ci *      separately, devm_gpio_free() must be used.
4108c2ecf20Sopenharmony_ci */
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ciint devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	unsigned *dr;
4158c2ecf20Sopenharmony_ci	int rc;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL);
4188c2ecf20Sopenharmony_ci	if (!dr)
4198c2ecf20Sopenharmony_ci		return -ENOMEM;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	rc = gpio_request(gpio, label);
4228c2ecf20Sopenharmony_ci	if (rc) {
4238c2ecf20Sopenharmony_ci		devres_free(dr);
4248c2ecf20Sopenharmony_ci		return rc;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	*dr = gpio;
4288c2ecf20Sopenharmony_ci	devres_add(dev, dr);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	return 0;
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpio_request);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci/**
4358c2ecf20Sopenharmony_ci *	devm_gpio_request_one - request a single GPIO with initial setup
4368c2ecf20Sopenharmony_ci *	@dev:   device to request for
4378c2ecf20Sopenharmony_ci *	@gpio:	the GPIO number
4388c2ecf20Sopenharmony_ci *	@flags:	GPIO configuration as specified by GPIOF_*
4398c2ecf20Sopenharmony_ci *	@label:	a literal description string of this GPIO
4408c2ecf20Sopenharmony_ci */
4418c2ecf20Sopenharmony_ciint devm_gpio_request_one(struct device *dev, unsigned gpio,
4428c2ecf20Sopenharmony_ci			  unsigned long flags, const char *label)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	unsigned *dr;
4458c2ecf20Sopenharmony_ci	int rc;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL);
4488c2ecf20Sopenharmony_ci	if (!dr)
4498c2ecf20Sopenharmony_ci		return -ENOMEM;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	rc = gpio_request_one(gpio, flags, label);
4528c2ecf20Sopenharmony_ci	if (rc) {
4538c2ecf20Sopenharmony_ci		devres_free(dr);
4548c2ecf20Sopenharmony_ci		return rc;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	*dr = gpio;
4588c2ecf20Sopenharmony_ci	devres_add(dev, dr);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	return 0;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpio_request_one);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci/**
4658c2ecf20Sopenharmony_ci *      devm_gpio_free - free a GPIO
4668c2ecf20Sopenharmony_ci *      @dev: device to free GPIO for
4678c2ecf20Sopenharmony_ci *      @gpio: GPIO to free
4688c2ecf20Sopenharmony_ci *
4698c2ecf20Sopenharmony_ci *      Except for the extra @dev argument, this function takes the
4708c2ecf20Sopenharmony_ci *      same arguments and performs the same function as gpio_free().
4718c2ecf20Sopenharmony_ci *      This function instead of gpio_free() should be used to manually
4728c2ecf20Sopenharmony_ci *      free GPIOs allocated with devm_gpio_request().
4738c2ecf20Sopenharmony_ci */
4748c2ecf20Sopenharmony_civoid devm_gpio_free(struct device *dev, unsigned int gpio)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
4788c2ecf20Sopenharmony_ci		&gpio));
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpio_free);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic void devm_gpio_chip_release(struct device *dev, void *res)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct gpio_chip *gc = *(struct gpio_chip **)res;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	gpiochip_remove(gc);
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci/**
4908c2ecf20Sopenharmony_ci * devm_gpiochip_add_data_with_key() - Resource managed gpiochip_add_data_with_key()
4918c2ecf20Sopenharmony_ci * @dev: pointer to the device that gpio_chip belongs to.
4928c2ecf20Sopenharmony_ci * @gc: the GPIO chip to register
4938c2ecf20Sopenharmony_ci * @data: driver-private data associated with this chip
4948c2ecf20Sopenharmony_ci * @lock_key: lockdep class for IRQ lock
4958c2ecf20Sopenharmony_ci * @request_key: lockdep class for IRQ request
4968c2ecf20Sopenharmony_ci *
4978c2ecf20Sopenharmony_ci * Context: potentially before irqs will work
4988c2ecf20Sopenharmony_ci *
4998c2ecf20Sopenharmony_ci * The gpio chip automatically be released when the device is unbound.
5008c2ecf20Sopenharmony_ci *
5018c2ecf20Sopenharmony_ci * Returns:
5028c2ecf20Sopenharmony_ci * A negative errno if the chip can't be registered, such as because the
5038c2ecf20Sopenharmony_ci * gc->base is invalid or already associated with a different chip.
5048c2ecf20Sopenharmony_ci * Otherwise it returns zero as a success code.
5058c2ecf20Sopenharmony_ci */
5068c2ecf20Sopenharmony_ciint devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, void *data,
5078c2ecf20Sopenharmony_ci				    struct lock_class_key *lock_key,
5088c2ecf20Sopenharmony_ci				    struct lock_class_key *request_key)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	struct gpio_chip **ptr;
5118c2ecf20Sopenharmony_ci	int ret;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
5148c2ecf20Sopenharmony_ci			     GFP_KERNEL);
5158c2ecf20Sopenharmony_ci	if (!ptr)
5168c2ecf20Sopenharmony_ci		return -ENOMEM;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
5198c2ecf20Sopenharmony_ci	if (ret < 0) {
5208c2ecf20Sopenharmony_ci		devres_free(ptr);
5218c2ecf20Sopenharmony_ci		return ret;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	*ptr = gc;
5258c2ecf20Sopenharmony_ci	devres_add(dev, ptr);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return 0;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiochip_add_data_with_key);
530