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